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
# 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
# Path to the default home dashboard. If this value is empty, then Grafana uses StaticRootPath + "dashboards/home.json"
default_home_dashboard_path =
#################################### Users ###############################
[users]
# disable user signup / registration
......
......@@ -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.
;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]
# disable user signup / registration
......
......@@ -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.
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]
> This have been replaced with dashboards [provisioning]({{< relref "../administration/provisioning" >}}) in 5.0+
......
......@@ -298,7 +298,7 @@ func (hs *HTTPServer) registerRoutes() {
dashboardRoute.Post("/calculate-diff", bind(dtos.CalculateDiffOptions{}), Wrap(CalculateDashboardDiff))
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.Post("/import", bind(dtos.ImportDashboardCommand{}), Wrap(ImportDashboard))
......
......@@ -19,7 +19,6 @@ import (
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
......@@ -315,15 +314,16 @@ func dashboardSaveErrorToApiResponse(err error) Response {
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}
if err := bus.Dispatch(&prefsQuery); err != nil {
if err := hs.Bus.Dispatch(&prefsQuery); err != nil {
return Error(500, "Failed to get preferences", err)
}
if prefsQuery.Result.HomeDashboardId != 0 {
slugQuery := models.GetDashboardRefByIdQuery{Id: prefsQuery.Result.HomeDashboardId}
err := bus.Dispatch(&slugQuery)
err := hs.Bus.Dispatch(&slugQuery)
if err == nil {
url := models.GetDashboardUrl(slugQuery.Result.Uid, slugQuery.Result.Slug)
dashRedirect := dtos.DashboardRedirect{RedirectUri: url}
......@@ -332,7 +332,11 @@ func GetHomeDashboard(c *models.ReqContext) Response {
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)
if err != nil {
return Error(500, "Failed to load home dashboard", err)
......
......@@ -3,6 +3,7 @@ package api
import (
"encoding/json"
"fmt"
"io/ioutil"
"testing"
"github.com/grafana/grafana/pkg/api/dtos"
......@@ -13,10 +14,58 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/provisioning"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require"
. "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.
// 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
......
......@@ -227,6 +227,7 @@ type Cfg struct {
AppUrl string
AppSubUrl string
ServeFromSubPath bool
StaticRootPath string
// build
BuildVersion string
......@@ -272,6 +273,9 @@ type Cfg struct {
DisableSanitizeHtml bool
EnterpriseLicensePath string
// Dashboards
DefaultHomeDashboardPath string
// Auth
LoginCookieName string
LoginMaxInactiveLifetimeDays int
......@@ -699,6 +703,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
return err
}
StaticRootPath = makeAbsolute(staticRoot, HomePath)
cfg.StaticRootPath = StaticRootPath
if err := cfg.validateStaticRootPath(); err != nil {
return err
......@@ -778,6 +783,8 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
return err
}
cfg.DefaultHomeDashboardPath = dashboards.Key("default_home_dashboard_path").MustString("")
// read data source proxy white list
DataProxyWhiteList = make(map[string]bool)
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