mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s Dashboards: Fix creating a dashboard inside a folder (#98982)
This commit is contained in:
parent
dbfc412ed8
commit
2a08c9ed82
@ -25,6 +25,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
pref "github.com/grafana/grafana/pkg/services/preference"
|
||||
@ -84,6 +85,8 @@ func dashboardGuardianResponse(err error) response.Response {
|
||||
// 403: forbiddenError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboard")
|
||||
defer span.End()
|
||||
@ -187,11 +190,23 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
|
||||
PublicDashboardEnabled: publicDashboardEnabled,
|
||||
}
|
||||
metrics.MFolderIDsAPICount.WithLabelValues(metrics.GetDashboard).Inc()
|
||||
// lookup folder title
|
||||
// nolint:staticcheck
|
||||
if dash.FolderID > 0 {
|
||||
// nolint:staticcheck
|
||||
query := dashboards.GetDashboardQuery{ID: dash.FolderID, OrgID: c.SignedInUser.GetOrgID()}
|
||||
// lookup folder title & url
|
||||
if dash.FolderUID != "" && hs.Features.IsEnabledGlobally(featuremgmt.FlagKubernetesFoldersServiceV2) {
|
||||
queryResult, err := hs.folderService.Get(ctx, &folder.GetFolderQuery{
|
||||
OrgID: c.SignedInUser.GetOrgID(),
|
||||
UID: &dash.FolderUID,
|
||||
SignedInUser: c.SignedInUser,
|
||||
})
|
||||
if errors.Is(err, dashboards.ErrFolderNotFound) {
|
||||
return response.Error(http.StatusNotFound, "Folder not found", err)
|
||||
}
|
||||
meta.FolderUid = queryResult.UID
|
||||
meta.FolderTitle = queryResult.Title
|
||||
meta.FolderId = queryResult.ID // nolint:staticcheck
|
||||
queryResult = queryResult.WithURL()
|
||||
meta.FolderUrl = queryResult.URL
|
||||
} else if dash.FolderID > 0 { // nolint:staticcheck
|
||||
query := dashboards.GetDashboardQuery{ID: dash.FolderID, OrgID: c.SignedInUser.GetOrgID()} // nolint:staticcheck
|
||||
metrics.MFolderIDsAPICount.WithLabelValues(metrics.GetDashboard).Inc()
|
||||
queryResult, err := hs.DashboardService.GetDashboard(ctx, &query)
|
||||
if err != nil {
|
||||
|
@ -369,16 +369,28 @@ func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, d
|
||||
}
|
||||
|
||||
// Validate folder
|
||||
if dash.FolderUID != "" {
|
||||
if !dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesFoldersServiceV2) {
|
||||
folder, err := dr.folderStore.GetFolderByUID(ctx, dash.OrgID, dash.FolderUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
|
||||
// nolint:staticcheck
|
||||
dash.FolderID = folder.ID
|
||||
if dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesFoldersServiceV2) {
|
||||
folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{
|
||||
OrgID: dash.OrgID,
|
||||
UID: &dash.FolderUID,
|
||||
ID: &dash.FolderID, // nolint:staticcheck
|
||||
SignedInUser: dto.User,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
|
||||
// nolint:staticcheck
|
||||
dash.FolderID = folder.ID
|
||||
dash.FolderUID = folder.UID
|
||||
} else if dash.FolderUID != "" {
|
||||
folder, err := dr.folderStore.GetFolderByUID(ctx, dash.OrgID, dash.FolderUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
|
||||
// nolint:staticcheck
|
||||
dash.FolderID = folder.ID
|
||||
} else if dash.FolderID != 0 { // nolint:staticcheck
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
|
||||
// nolint:staticcheck
|
||||
@ -2171,6 +2183,15 @@ func LegacySaveCommandToUnstructured(cmd *dashboards.SaveDashboardCommand, names
|
||||
finalObj.SetNamespace(namespace)
|
||||
finalObj.SetGroupVersionKind(v0alpha1.DashboardResourceInfo.GroupVersionKind())
|
||||
|
||||
if cmd.FolderUID != "" {
|
||||
meta, err := utils.MetaAccessor(&finalObj)
|
||||
if err != nil {
|
||||
return finalObj, err
|
||||
}
|
||||
|
||||
meta.SetFolder(cmd.FolderUID)
|
||||
}
|
||||
|
||||
return finalObj, nil
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
@ -19,10 +21,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@ -860,6 +862,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
||||
|
||||
guardianMock := &guardian.FakeDashboardGuardian{
|
||||
CanSaveValue: canSave,
|
||||
CanViewValue: true,
|
||||
}
|
||||
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
@ -873,6 +876,9 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
folderStore2 := folderimpl.ProvideStore(sqlStore)
|
||||
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
|
||||
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||
dashboardService, err := ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore,
|
||||
@ -880,7 +886,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
||||
folderPermissions,
|
||||
dashboardPermissions,
|
||||
ac,
|
||||
foldertest.NewFakeService(),
|
||||
folderService,
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
nil,
|
||||
@ -942,7 +948,9 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
folderStore2 := folderimpl.ProvideStore(sqlStore)
|
||||
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
|
||||
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||
dashboardPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
service, err := ProvideDashboardServiceImpl(
|
||||
@ -951,7 +959,7 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
|
||||
folderPermissions,
|
||||
dashboardPermissions,
|
||||
actest.FakeAccessControl{},
|
||||
foldertest.NewFakeService(),
|
||||
folderService,
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
nil,
|
||||
@ -975,13 +983,16 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
|
||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, features, tagimpl.ProvideService(sqlStore))
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
folderStore2 := folderimpl.ProvideStore(sqlStore)
|
||||
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
|
||||
service, err := ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore,
|
||||
featuremgmt.WithFeatures(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
actest.FakeAccessControl{},
|
||||
foldertest.NewFakeService(),
|
||||
folderService,
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
nil,
|
||||
@ -1024,13 +1035,16 @@ func saveTestDashboard(t *testing.T, title string, orgID int64, folderUID string
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||
dashboardPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
folderStore2 := folderimpl.ProvideStore(sqlStore)
|
||||
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
|
||||
service, err := ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore,
|
||||
features,
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
dashboardPermissions,
|
||||
actest.FakeAccessControl{},
|
||||
foldertest.NewFakeService(),
|
||||
folderService,
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
nil,
|
||||
@ -1079,6 +1093,9 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
|
||||
require.NoError(t, err)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
folderPermissions := accesscontrolmock.NewMockedPermissionsService()
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
folderStore2 := folderimpl.ProvideStore(sqlStore)
|
||||
folderService := folderimpl.ProvideService(folderStore2, actest.FakeAccessControl{ExpectedEvaluate: true}, bus.ProvideBus(tracer), dashboardStore, folderStore, sqlStore, features, supportbundlestest.NewFakeBundleService(), cfg, nil, tracer)
|
||||
folderPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
service, err := ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore,
|
||||
@ -1086,7 +1103,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
|
||||
folderPermissions,
|
||||
accesscontrolmock.NewMockedPermissionsService(),
|
||||
actest.FakeAccessControl{},
|
||||
foldertest.NewFakeService(),
|
||||
folderService,
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
nil,
|
||||
|
@ -40,7 +40,6 @@ func TestDashboardService(t *testing.T) {
|
||||
defer fakeStore.AssertExpectations(t)
|
||||
|
||||
folderSvc := foldertest.NewFakeService()
|
||||
|
||||
service := &DashboardServiceImpl{
|
||||
cfg: setting.NewCfg(),
|
||||
log: log.New("test.logger"),
|
||||
@ -48,6 +47,9 @@ func TestDashboardService(t *testing.T) {
|
||||
folderService: folderSvc,
|
||||
features: featuremgmt.WithFeatures(),
|
||||
}
|
||||
folderStore := foldertest.FakeFolderStore{}
|
||||
folderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(nil, dashboards.ErrFolderNotFound).Once()
|
||||
service.folderStore = &folderStore
|
||||
|
||||
origNewDashboardGuardian := guardian.New
|
||||
defer func() { guardian.New = origNewDashboardGuardian }()
|
||||
@ -102,9 +104,8 @@ func TestDashboardService(t *testing.T) {
|
||||
t.Run("Should return validation error if a folder that is specified can't be found", func(t *testing.T) {
|
||||
dto.Dashboard = dashboards.NewDashboard("Dash")
|
||||
dto.Dashboard.FolderUID = "non-existing-folder"
|
||||
folderStore := foldertest.FakeFolderStore{}
|
||||
folderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(nil, dashboards.ErrFolderNotFound).Once()
|
||||
service.folderStore = &folderStore
|
||||
folderSvc := foldertest.FakeService{ExpectedError: dashboards.ErrFolderNotFound}
|
||||
service.folderService = &folderSvc
|
||||
_, err := service.SaveDashboard(context.Background(), dto, false)
|
||||
require.Equal(t, err, dashboards.ErrFolderNotFound)
|
||||
})
|
||||
@ -1835,6 +1836,7 @@ func TestLegacySaveCommandToUnstructured(t *testing.T) {
|
||||
namespace := "test-namespace"
|
||||
t.Run("successfully converts save command to unstructured", func(t *testing.T) {
|
||||
cmd := &dashboards.SaveDashboardCommand{
|
||||
FolderUID: "folder-uid",
|
||||
Dashboard: simplejson.NewFromAny(map[string]any{"test": "test", "title": "testing slugify", "uid": "test-uid"}),
|
||||
}
|
||||
|
||||
@ -1845,6 +1847,7 @@ func TestLegacySaveCommandToUnstructured(t *testing.T) {
|
||||
assert.Equal(t, "test-namespace", result.GetNamespace())
|
||||
spec := result.Object["spec"].(map[string]any)
|
||||
assert.Equal(t, spec["version"], 1)
|
||||
assert.Equal(t, result.GetAnnotations(), map[string]string{utils.AnnoKeyFolder: "folder-uid"})
|
||||
})
|
||||
|
||||
t.Run("should increase version when called", func(t *testing.T) {
|
||||
@ -1856,6 +1859,8 @@ func TestLegacySaveCommandToUnstructured(t *testing.T) {
|
||||
assert.NotNil(t, result)
|
||||
spec := result.Object["spec"].(map[string]any)
|
||||
assert.Equal(t, spec["version"], float64(2))
|
||||
// folder annotation should not be set if not inside a folder
|
||||
assert.Equal(t, result.GetAnnotations(), map[string]string(nil))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -303,10 +303,14 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
|
||||
dashboardPermissions := acmock.NewMockedPermissionsService()
|
||||
dashboardPermissions.On("SetPermissions", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]accesscontrol.ResourcePermission{}, nil)
|
||||
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
|
||||
var expectedFolder *folder.Folder
|
||||
if dash.FolderUID != "" || dash.FolderID != 0 { // nolint:staticcheck
|
||||
expectedFolder = &folder.Folder{ID: folderID, UID: folderUID}
|
||||
}
|
||||
service, err := dashboardservice.ProvideDashboardServiceImpl(
|
||||
cfg, dashboardStore, folderStore,
|
||||
features, folderPermissions, dashboardPermissions, ac,
|
||||
foldertest.NewFakeService(),
|
||||
&foldertest.FakeService{ExpectedFolder: expectedFolder},
|
||||
folder.NewFakeStore(),
|
||||
nil,
|
||||
nil,
|
||||
|
Loading…
Reference in New Issue
Block a user