mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 18:13:09 +08:00
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>
This commit is contained in:
@ -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 @@
|
|||||||
# 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`.
|
|||||||
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() {
|
|||||||
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 (
|
|||||||
"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 {
|
|||||||
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 {
|
|||||||
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
|
|||||||
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 (
|
|||||||
"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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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", "")
|
||||||
|
Reference in New Issue
Block a user