Provisioning: Fix dual write of folders (#80140)
* Provisioning: Store folders in folders table * Solve linting issues * Remove a comment
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
alertmodels "github.com/grafana/grafana/pkg/services/alerting/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
)
|
||||
@@ -41,7 +42,7 @@ type DashboardProvisioningService interface {
|
||||
GetProvisionedDashboardData(ctx context.Context, name string) ([]*DashboardProvisioning, error)
|
||||
GetProvisionedDashboardDataByDashboardID(ctx context.Context, dashboardID int64) (*DashboardProvisioning, error)
|
||||
GetProvisionedDashboardDataByDashboardUID(ctx context.Context, orgID int64, dashboardUID string) (*DashboardProvisioning, error)
|
||||
SaveFolderForProvisionedDashboards(context.Context, *SaveDashboardDTO) (*Dashboard, error)
|
||||
SaveFolderForProvisionedDashboards(context.Context, *folder.CreateFolderCommand) (*folder.Folder, error)
|
||||
SaveProvisionedDashboard(ctx context.Context, dto *SaveDashboardDTO, provisioning *DashboardProvisioning) (*Dashboard, error)
|
||||
UnprovisionDashboard(ctx context.Context, dashboardID int64) error
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Code generated by mockery v2.28.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.38.0. DO NOT EDIT.
|
||||
|
||||
package dashboards
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
folder "github.com/grafana/grafana/pkg/services/folder"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -17,6 +18,10 @@ type FakeDashboardProvisioning struct {
|
||||
func (_m *FakeDashboardProvisioning) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *DeleteOrphanedProvisionedDashboardsCommand) error {
|
||||
ret := _m.Called(ctx, cmd)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteOrphanedProvisionedDashboards")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *DeleteOrphanedProvisionedDashboardsCommand) error); ok {
|
||||
r0 = rf(ctx, cmd)
|
||||
@@ -31,6 +36,10 @@ func (_m *FakeDashboardProvisioning) DeleteOrphanedProvisionedDashboards(ctx con
|
||||
func (_m *FakeDashboardProvisioning) DeleteProvisionedDashboard(ctx context.Context, dashboardID int64, orgID int64) error {
|
||||
ret := _m.Called(ctx, dashboardID, orgID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteProvisionedDashboard")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) error); ok {
|
||||
r0 = rf(ctx, dashboardID, orgID)
|
||||
@@ -45,6 +54,10 @@ func (_m *FakeDashboardProvisioning) DeleteProvisionedDashboard(ctx context.Cont
|
||||
func (_m *FakeDashboardProvisioning) GetProvisionedDashboardData(ctx context.Context, name string) ([]*DashboardProvisioning, error) {
|
||||
ret := _m.Called(ctx, name)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProvisionedDashboardData")
|
||||
}
|
||||
|
||||
var r0 []*DashboardProvisioning
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]*DashboardProvisioning, error)); ok {
|
||||
@@ -71,6 +84,10 @@ func (_m *FakeDashboardProvisioning) GetProvisionedDashboardData(ctx context.Con
|
||||
func (_m *FakeDashboardProvisioning) GetProvisionedDashboardDataByDashboardID(ctx context.Context, dashboardID int64) (*DashboardProvisioning, error) {
|
||||
ret := _m.Called(ctx, dashboardID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProvisionedDashboardDataByDashboardID")
|
||||
}
|
||||
|
||||
var r0 *DashboardProvisioning
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) (*DashboardProvisioning, error)); ok {
|
||||
@@ -97,6 +114,10 @@ func (_m *FakeDashboardProvisioning) GetProvisionedDashboardDataByDashboardID(ct
|
||||
func (_m *FakeDashboardProvisioning) GetProvisionedDashboardDataByDashboardUID(ctx context.Context, orgID int64, dashboardUID string) (*DashboardProvisioning, error) {
|
||||
ret := _m.Called(ctx, orgID, dashboardUID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProvisionedDashboardDataByDashboardUID")
|
||||
}
|
||||
|
||||
var r0 *DashboardProvisioning
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*DashboardProvisioning, error)); ok {
|
||||
@@ -120,23 +141,27 @@ func (_m *FakeDashboardProvisioning) GetProvisionedDashboardDataByDashboardUID(c
|
||||
}
|
||||
|
||||
// SaveFolderForProvisionedDashboards provides a mock function with given fields: _a0, _a1
|
||||
func (_m *FakeDashboardProvisioning) SaveFolderForProvisionedDashboards(_a0 context.Context, _a1 *SaveDashboardDTO) (*Dashboard, error) {
|
||||
func (_m *FakeDashboardProvisioning) SaveFolderForProvisionedDashboards(_a0 context.Context, _a1 *folder.CreateFolderCommand) (*folder.Folder, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *Dashboard
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveFolderForProvisionedDashboards")
|
||||
}
|
||||
|
||||
var r0 *folder.Folder
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO) (*Dashboard, error)); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *folder.CreateFolderCommand) (*folder.Folder, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO) *Dashboard); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *folder.CreateFolderCommand) *folder.Folder); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*Dashboard)
|
||||
r0 = ret.Get(0).(*folder.Folder)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *SaveDashboardDTO) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *folder.CreateFolderCommand) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -149,6 +174,10 @@ func (_m *FakeDashboardProvisioning) SaveFolderForProvisionedDashboards(_a0 cont
|
||||
func (_m *FakeDashboardProvisioning) SaveProvisionedDashboard(ctx context.Context, dto *SaveDashboardDTO, provisioning *DashboardProvisioning) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, dto, provisioning)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveProvisionedDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, *DashboardProvisioning) (*Dashboard, error)); ok {
|
||||
@@ -175,6 +204,10 @@ func (_m *FakeDashboardProvisioning) SaveProvisionedDashboard(ctx context.Contex
|
||||
func (_m *FakeDashboardProvisioning) UnprovisionDashboard(ctx context.Context, dashboardID int64) error {
|
||||
ret := _m.Called(ctx, dashboardID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UnprovisionDashboard")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(ctx, dashboardID)
|
||||
@@ -185,13 +218,12 @@ func (_m *FakeDashboardProvisioning) UnprovisionDashboard(ctx context.Context, d
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewFakeDashboardProvisioning interface {
|
||||
// NewFakeDashboardProvisioning creates a new instance of FakeDashboardProvisioning. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewFakeDashboardProvisioning(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewFakeDashboardProvisioning creates a new instance of FakeDashboardProvisioning. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeDashboardProvisioning(t mockConstructorTestingTNewFakeDashboardProvisioning) *FakeDashboardProvisioning {
|
||||
}) *FakeDashboardProvisioning {
|
||||
mock := &FakeDashboardProvisioning{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// Code generated by mockery v2.38.0. DO NOT EDIT.
|
||||
|
||||
package dashboards
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
identity "github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
model "github.com/grafana/grafana/pkg/services/search/model"
|
||||
)
|
||||
|
||||
@@ -18,6 +20,10 @@ type FakeDashboardService struct {
|
||||
func (_m *FakeDashboardService) BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*SaveDashboardCommand, error) {
|
||||
ret := _m.Called(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for BuildSaveDashboardCommand")
|
||||
}
|
||||
|
||||
var r0 *SaveDashboardCommand
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, bool, bool) (*SaveDashboardCommand, error)); ok {
|
||||
@@ -40,23 +46,27 @@ func (_m *FakeDashboardService) BuildSaveDashboardCommand(ctx context.Context, d
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CountInFolder provides a mock function with given fields: ctx, orgID, folderUID, _a3
|
||||
func (_m *FakeDashboardService) CountInFolder(ctx context.Context, orgID int64, folderUID string, _a3 identity.Requester) (int64, error) {
|
||||
ret := _m.Called(ctx, orgID, folderUID, _a3)
|
||||
// CountInFolder provides a mock function with given fields: ctx, orgID, folderUID, user
|
||||
func (_m *FakeDashboardService) CountInFolder(ctx context.Context, orgID int64, folderUID string, user identity.Requester) (int64, error) {
|
||||
ret := _m.Called(ctx, orgID, folderUID, user)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CountInFolder")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string, identity.Requester) (int64, error)); ok {
|
||||
return rf(ctx, orgID, folderUID, _a3)
|
||||
return rf(ctx, orgID, folderUID, user)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string, identity.Requester) int64); ok {
|
||||
r0 = rf(ctx, orgID, folderUID, _a3)
|
||||
r0 = rf(ctx, orgID, folderUID, user)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64, string, identity.Requester) error); ok {
|
||||
r1 = rf(ctx, orgID, folderUID, _a3)
|
||||
r1 = rf(ctx, orgID, folderUID, user)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -68,6 +78,10 @@ func (_m *FakeDashboardService) CountInFolder(ctx context.Context, orgID int64,
|
||||
func (_m *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
|
||||
ret := _m.Called(ctx, dashboardId, orgId)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteDashboard")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) error); ok {
|
||||
r0 = rf(ctx, dashboardId, orgId)
|
||||
@@ -82,6 +96,10 @@ func (_m *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId
|
||||
func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for FindDashboards")
|
||||
}
|
||||
|
||||
var r0 []DashboardSearchProjection
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)); ok {
|
||||
@@ -108,6 +126,10 @@ func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindP
|
||||
func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardQuery) (*Dashboard, error)); ok {
|
||||
@@ -134,6 +156,10 @@ func (_m *FakeDashboardService) GetDashboard(ctx context.Context, query *GetDash
|
||||
func (_m *FakeDashboardService) GetDashboardTags(ctx context.Context, query *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboardTags")
|
||||
}
|
||||
|
||||
var r0 []*DashboardTagCloudItem
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error)); ok {
|
||||
@@ -160,6 +186,10 @@ func (_m *FakeDashboardService) GetDashboardTags(ctx context.Context, query *Get
|
||||
func (_m *FakeDashboardService) GetDashboardUIDByID(ctx context.Context, query *GetDashboardRefByIDQuery) (*DashboardRef, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboardUIDByID")
|
||||
}
|
||||
|
||||
var r0 *DashboardRef
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardRefByIDQuery) (*DashboardRef, error)); ok {
|
||||
@@ -186,6 +216,10 @@ func (_m *FakeDashboardService) GetDashboardUIDByID(ctx context.Context, query *
|
||||
func (_m *FakeDashboardService) GetDashboards(ctx context.Context, query *GetDashboardsQuery) ([]*Dashboard, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboards")
|
||||
}
|
||||
|
||||
var r0 []*Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardsQuery) ([]*Dashboard, error)); ok {
|
||||
@@ -208,10 +242,44 @@ func (_m *FakeDashboardService) GetDashboards(ctx context.Context, query *GetDas
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetDashboardsSharedWithUser provides a mock function with given fields: ctx, user
|
||||
func (_m *FakeDashboardService) GetDashboardsSharedWithUser(ctx context.Context, user identity.Requester) ([]*Dashboard, error) {
|
||||
ret := _m.Called(ctx, user)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboardsSharedWithUser")
|
||||
}
|
||||
|
||||
var r0 []*Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, identity.Requester) ([]*Dashboard, error)); ok {
|
||||
return rf(ctx, user)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, identity.Requester) []*Dashboard); ok {
|
||||
r0 = rf(ctx, user)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*Dashboard)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, identity.Requester) error); ok {
|
||||
r1 = rf(ctx, user)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ImportDashboard provides a mock function with given fields: ctx, dto
|
||||
func (_m *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, dto)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ImportDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO) (*Dashboard, error)); ok {
|
||||
@@ -238,6 +306,10 @@ func (_m *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDa
|
||||
func (_m *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, dto, allowUiUpdate)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *SaveDashboardDTO, bool) (*Dashboard, error)); ok {
|
||||
@@ -264,6 +336,10 @@ func (_m *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDash
|
||||
func (_m *FakeDashboardService) SearchDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) (model.HitList, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SearchDashboards")
|
||||
}
|
||||
|
||||
var r0 model.HitList
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) (model.HitList, error)); ok {
|
||||
@@ -286,38 +362,12 @@ func (_m *FakeDashboardService) SearchDashboards(ctx context.Context, query *Fin
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (_m *FakeDashboardService) GetDashboardsSharedWithUser(ctx context.Context, user identity.Requester) ([]*Dashboard, error) {
|
||||
ret := _m.Called(ctx, user)
|
||||
|
||||
var r0 []*Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, identity.Requester) ([]*Dashboard, error)); ok {
|
||||
return rf(ctx, user)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, identity.Requester) []*Dashboard); ok {
|
||||
r0 = rf(ctx, user)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*Dashboard)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, identity.Requester) error); ok {
|
||||
r1 = rf(ctx, user)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewFakeDashboardService interface {
|
||||
// NewFakeDashboardService creates a new instance of FakeDashboardService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewFakeDashboardService(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewFakeDashboardService creates a new instance of FakeDashboardService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeDashboardService(t mockConstructorTestingTNewFakeDashboardService) *FakeDashboardService {
|
||||
}) *FakeDashboardService {
|
||||
mock := &FakeDashboardService{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
||||
@@ -349,42 +349,17 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt
|
||||
return dash, nil
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error) {
|
||||
dto.User = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions)
|
||||
cmd, err := dr.BuildSaveDashboardCommand(ctx, dto, false, false)
|
||||
func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.Context, dto *folder.CreateFolderCommand) (*folder.Folder, error) {
|
||||
dto.SignedInUser = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions)
|
||||
|
||||
f, err := dr.folderService.Create(ctx, dto)
|
||||
if err != nil {
|
||||
dr.log.Error("failed to create folder for provisioned dashboards", "folder", dto.Title, "org", dto.OrgID, "err", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dash, err := dr.dashboardStore.SaveDashboard(ctx, *cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dashAlertInfo := alerting.DashAlertInfo{
|
||||
User: dto.User,
|
||||
Dash: dash,
|
||||
OrgID: dto.OrgID,
|
||||
}
|
||||
|
||||
// extract/save legacy alerts only if legacy alerting is enabled
|
||||
if setting.IsLegacyAlertingEnabled() {
|
||||
alerts, err := dr.dashAlertExtractor.GetAlerts(ctx, dashAlertInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = dr.dashboardStore.SaveAlerts(ctx, dash.ID, alerts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if dto.Dashboard.ID == 0 {
|
||||
dr.setDefaultPermissions(ctx, dto, dash, true)
|
||||
}
|
||||
|
||||
return dash, nil
|
||||
dr.setDefaultFolderPermissions(ctx, dto, f, true)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO,
|
||||
@@ -532,6 +507,35 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
|
||||
}
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) setDefaultFolderPermissions(ctx context.Context, cmd *folder.CreateFolderCommand, f *folder.Folder, provisioned bool) {
|
||||
inFolder := f.ParentUID != ""
|
||||
var permissions []accesscontrol.SetResourcePermissionCommand
|
||||
|
||||
if !provisioned {
|
||||
namespaceID, userIDstr := cmd.SignedInUser.GetNamespacedID()
|
||||
userID, err := identity.IntIdentifier(namespaceID, userIDstr)
|
||||
|
||||
if err != nil {
|
||||
dr.log.Error("Could not make user admin", "folder", cmd.Title, "namespaceID", namespaceID, "userID", userID, "error", err)
|
||||
} else if namespaceID == identity.NamespaceUser && userID > 0 {
|
||||
permissions = append(permissions, accesscontrol.SetResourcePermissionCommand{
|
||||
UserID: userID, Permission: dashboardaccess.PERMISSION_ADMIN.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if !inFolder {
|
||||
permissions = append(permissions, []accesscontrol.SetResourcePermissionCommand{
|
||||
{BuiltinRole: string(org.RoleEditor), Permission: dashboardaccess.PERMISSION_EDIT.String()},
|
||||
{BuiltinRole: string(org.RoleViewer), Permission: dashboardaccess.PERMISSION_VIEW.String()},
|
||||
}...)
|
||||
}
|
||||
|
||||
if _, err := dr.folderPermissions.SetPermissions(ctx, cmd.OrgID, f.UID, permissions...); err != nil {
|
||||
dr.log.Error("Could not set default folder permissions", "folder", f.Title, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) GetDashboard(ctx context.Context, query *dashboards.GetDashboardQuery) (*dashboards.Dashboard, error) {
|
||||
return dr.dashboardStore.GetDashboard(ctx, query)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.28.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.38.0. DO NOT EDIT.
|
||||
|
||||
package dashboards
|
||||
|
||||
@@ -20,6 +20,10 @@ type FakeDashboardStore struct {
|
||||
func (_m *FakeDashboardStore) Count(_a0 context.Context, _a1 *quota.ScopeParameters) (*quota.Map, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Count")
|
||||
}
|
||||
|
||||
var r0 *quota.Map
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *quota.ScopeParameters) (*quota.Map, error)); ok {
|
||||
@@ -46,6 +50,10 @@ func (_m *FakeDashboardStore) Count(_a0 context.Context, _a1 *quota.ScopeParamet
|
||||
func (_m *FakeDashboardStore) CountDashboardsInFolder(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error) {
|
||||
ret := _m.Called(ctx, request)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CountDashboardsInFolder")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *CountDashboardsInFolderRequest) (int64, error)); ok {
|
||||
@@ -70,6 +78,10 @@ func (_m *FakeDashboardStore) CountDashboardsInFolder(ctx context.Context, reque
|
||||
func (_m *FakeDashboardStore) DeleteDashboard(ctx context.Context, cmd *DeleteDashboardCommand) error {
|
||||
ret := _m.Called(ctx, cmd)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteDashboard")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *DeleteDashboardCommand) error); ok {
|
||||
r0 = rf(ctx, cmd)
|
||||
@@ -84,6 +96,10 @@ func (_m *FakeDashboardStore) DeleteDashboard(ctx context.Context, cmd *DeleteDa
|
||||
func (_m *FakeDashboardStore) DeleteDashboardsInFolder(ctx context.Context, request *DeleteDashboardsInFolderRequest) error {
|
||||
ret := _m.Called(ctx, request)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteDashboardsInFolder")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *DeleteDashboardsInFolderRequest) error); ok {
|
||||
r0 = rf(ctx, request)
|
||||
@@ -98,6 +114,10 @@ func (_m *FakeDashboardStore) DeleteDashboardsInFolder(ctx context.Context, requ
|
||||
func (_m *FakeDashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *DeleteOrphanedProvisionedDashboardsCommand) error {
|
||||
ret := _m.Called(ctx, cmd)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteOrphanedProvisionedDashboards")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *DeleteOrphanedProvisionedDashboardsCommand) error); ok {
|
||||
r0 = rf(ctx, cmd)
|
||||
@@ -112,6 +132,10 @@ func (_m *FakeDashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Co
|
||||
func (_m *FakeDashboardStore) FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for FindDashboards")
|
||||
}
|
||||
|
||||
var r0 []DashboardSearchProjection
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error)); ok {
|
||||
@@ -138,6 +162,10 @@ func (_m *FakeDashboardStore) FindDashboards(ctx context.Context, query *FindPer
|
||||
func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardQuery) (*Dashboard, error)); ok {
|
||||
@@ -164,6 +192,10 @@ func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *GetDashbo
|
||||
func (_m *FakeDashboardStore) GetDashboardTags(ctx context.Context, query *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboardTags")
|
||||
}
|
||||
|
||||
var r0 []*DashboardTagCloudItem
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error)); ok {
|
||||
@@ -190,6 +222,10 @@ func (_m *FakeDashboardStore) GetDashboardTags(ctx context.Context, query *GetDa
|
||||
func (_m *FakeDashboardStore) GetDashboardUIDByID(ctx context.Context, query *GetDashboardRefByIDQuery) (*DashboardRef, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboardUIDByID")
|
||||
}
|
||||
|
||||
var r0 *DashboardRef
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardRefByIDQuery) (*DashboardRef, error)); ok {
|
||||
@@ -216,6 +252,10 @@ func (_m *FakeDashboardStore) GetDashboardUIDByID(ctx context.Context, query *Ge
|
||||
func (_m *FakeDashboardStore) GetDashboards(ctx context.Context, query *GetDashboardsQuery) ([]*Dashboard, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboards")
|
||||
}
|
||||
|
||||
var r0 []*Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardsQuery) ([]*Dashboard, error)); ok {
|
||||
@@ -242,6 +282,10 @@ func (_m *FakeDashboardStore) GetDashboards(ctx context.Context, query *GetDashb
|
||||
func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query *GetDashboardsByPluginIDQuery) ([]*Dashboard, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetDashboardsByPluginID")
|
||||
}
|
||||
|
||||
var r0 []*Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardsByPluginIDQuery) ([]*Dashboard, error)); ok {
|
||||
@@ -268,6 +312,10 @@ func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query
|
||||
func (_m *FakeDashboardStore) GetProvisionedDashboardData(ctx context.Context, name string) ([]*DashboardProvisioning, error) {
|
||||
ret := _m.Called(ctx, name)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProvisionedDashboardData")
|
||||
}
|
||||
|
||||
var r0 []*DashboardProvisioning
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]*DashboardProvisioning, error)); ok {
|
||||
@@ -294,6 +342,10 @@ func (_m *FakeDashboardStore) GetProvisionedDashboardData(ctx context.Context, n
|
||||
func (_m *FakeDashboardStore) GetProvisionedDataByDashboardID(ctx context.Context, dashboardID int64) (*DashboardProvisioning, error) {
|
||||
ret := _m.Called(ctx, dashboardID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProvisionedDataByDashboardID")
|
||||
}
|
||||
|
||||
var r0 *DashboardProvisioning
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) (*DashboardProvisioning, error)); ok {
|
||||
@@ -320,6 +372,10 @@ func (_m *FakeDashboardStore) GetProvisionedDataByDashboardID(ctx context.Contex
|
||||
func (_m *FakeDashboardStore) GetProvisionedDataByDashboardUID(ctx context.Context, orgID int64, dashboardUID string) (*DashboardProvisioning, error) {
|
||||
ret := _m.Called(ctx, orgID, dashboardUID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetProvisionedDataByDashboardUID")
|
||||
}
|
||||
|
||||
var r0 *DashboardProvisioning
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*DashboardProvisioning, error)); ok {
|
||||
@@ -346,6 +402,10 @@ func (_m *FakeDashboardStore) GetProvisionedDataByDashboardUID(ctx context.Conte
|
||||
func (_m *FakeDashboardStore) SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error {
|
||||
ret := _m.Called(ctx, dashID, alerts)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveAlerts")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64, []*models.Alert) error); ok {
|
||||
r0 = rf(ctx, dashID, alerts)
|
||||
@@ -360,6 +420,10 @@ func (_m *FakeDashboardStore) SaveAlerts(ctx context.Context, dashID int64, aler
|
||||
func (_m *FakeDashboardStore) SaveDashboard(ctx context.Context, cmd SaveDashboardCommand) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, cmd)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, SaveDashboardCommand) (*Dashboard, error)); ok {
|
||||
@@ -386,6 +450,10 @@ func (_m *FakeDashboardStore) SaveDashboard(ctx context.Context, cmd SaveDashboa
|
||||
func (_m *FakeDashboardStore) SaveProvisionedDashboard(ctx context.Context, cmd SaveDashboardCommand, provisioning *DashboardProvisioning) (*Dashboard, error) {
|
||||
ret := _m.Called(ctx, cmd, provisioning)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveProvisionedDashboard")
|
||||
}
|
||||
|
||||
var r0 *Dashboard
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, SaveDashboardCommand, *DashboardProvisioning) (*Dashboard, error)); ok {
|
||||
@@ -412,6 +480,10 @@ func (_m *FakeDashboardStore) SaveProvisionedDashboard(ctx context.Context, cmd
|
||||
func (_m *FakeDashboardStore) UnprovisionDashboard(ctx context.Context, id int64) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UnprovisionDashboard")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
@@ -426,6 +498,10 @@ func (_m *FakeDashboardStore) UnprovisionDashboard(ctx context.Context, id int64
|
||||
func (_m *FakeDashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dashboard *Dashboard, overwrite bool) (bool, error) {
|
||||
ret := _m.Called(ctx, dashboard, overwrite)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ValidateDashboardBeforeSave")
|
||||
}
|
||||
|
||||
var r0 bool
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *Dashboard, bool) (bool, error)); ok {
|
||||
@@ -446,13 +522,12 @@ func (_m *FakeDashboardStore) ValidateDashboardBeforeSave(ctx context.Context, d
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewFakeDashboardStore interface {
|
||||
// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewFakeDashboardStore(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeDashboardStore(t mockConstructorTestingTNewFakeDashboardStore) *FakeDashboardStore {
|
||||
}) *FakeDashboardStore {
|
||||
mock := &FakeDashboardStore{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -177,10 +178,12 @@ func (ss *sqlStore) Get(ctx context.Context, q folder.GetFolderQuery) (*folder.F
|
||||
return folder.ErrDatabaseError.Errorf("failed to get folder: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return folder.ErrFolderNotFound.Errorf("folder not found")
|
||||
// embed dashboards.ErrFolderNotFound
|
||||
return folder.ErrFolderNotFound.Errorf("%w", dashboards.ErrFolderNotFound)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return foldr.WithURL(), err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
alert_models "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@@ -107,13 +108,12 @@ func (prov *defaultAlertRuleProvisioner) getOrCreateFolderUID(
|
||||
|
||||
// dashboard folder not found. create one.
|
||||
if errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
dash := &dashboards.SaveDashboardDTO{}
|
||||
dash.Dashboard = dashboards.NewDashboardFolder(folderName)
|
||||
dash.Dashboard.IsFolder = true
|
||||
dash.Overwrite = true
|
||||
dash.OrgID = orgID
|
||||
dash.Dashboard.SetUID(util.GenerateShortUID())
|
||||
dbDash, err := prov.dashboardProvService.SaveFolderForProvisionedDashboards(ctx, dash)
|
||||
createCmd := &folder.CreateFolderCommand{
|
||||
OrgID: orgID,
|
||||
UID: util.GenerateShortUID(),
|
||||
Title: folderName,
|
||||
}
|
||||
dbDash, err := prov.dashboardProvService.SaveFolderForProvisionedDashboards(ctx, createCmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning/utils"
|
||||
)
|
||||
@@ -23,7 +24,7 @@ type DashboardProvisioner interface {
|
||||
}
|
||||
|
||||
// DashboardProvisionerFactory creates DashboardProvisioners based on input
|
||||
type DashboardProvisionerFactory func(context.Context, string, dashboards.DashboardProvisioningService, org.Service, utils.DashboardStore) (DashboardProvisioner, error)
|
||||
type DashboardProvisionerFactory func(context.Context, string, dashboards.DashboardProvisioningService, org.Service, utils.DashboardStore, folder.Service) (DashboardProvisioner, error)
|
||||
|
||||
// Provisioner is responsible for syncing dashboard from disk to Grafana's database.
|
||||
type Provisioner struct {
|
||||
@@ -39,7 +40,7 @@ func (provider *Provisioner) HasDashboardSources() bool {
|
||||
}
|
||||
|
||||
// New returns a new DashboardProvisioner
|
||||
func New(ctx context.Context, configDirectory string, provisioner dashboards.DashboardProvisioningService, orgService org.Service, dashboardStore utils.DashboardStore) (DashboardProvisioner, error) {
|
||||
func New(ctx context.Context, configDirectory string, provisioner dashboards.DashboardProvisioningService, orgService org.Service, dashboardStore utils.DashboardStore, folderService folder.Service) (DashboardProvisioner, error) {
|
||||
logger := log.New("provisioning.dashboard")
|
||||
cfgReader := &configReader{path: configDirectory, log: logger, orgService: orgService}
|
||||
configs, err := cfgReader.readConfig(ctx)
|
||||
@@ -47,7 +48,7 @@ func New(ctx context.Context, configDirectory string, provisioner dashboards.Das
|
||||
return nil, fmt.Errorf("%v: %w", "Failed to read dashboards config", err)
|
||||
}
|
||||
|
||||
fileReaders, err := getFileReaders(configs, logger, provisioner, dashboardStore)
|
||||
fileReaders, err := getFileReaders(configs, logger, provisioner, dashboardStore, folderService)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v: %w", "Failed to initialize file readers", err)
|
||||
}
|
||||
@@ -66,6 +67,8 @@ func New(ctx context.Context, configDirectory string, provisioner dashboards.Das
|
||||
// Provision scans the disk for dashboards and updates
|
||||
// the database with the latest versions of those dashboards.
|
||||
func (provider *Provisioner) Provision(ctx context.Context) error {
|
||||
provider.log.Info("starting to provision dashboards")
|
||||
|
||||
for _, reader := range provider.fileReaders {
|
||||
if err := reader.walkDisk(ctx); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@@ -79,6 +82,7 @@ func (provider *Provisioner) Provision(ctx context.Context) error {
|
||||
}
|
||||
|
||||
provider.duplicateValidator.validate()
|
||||
provider.log.Info("finished to provision dashboards")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -127,14 +131,24 @@ func (provider *Provisioner) GetAllowUIUpdatesFromConfig(name string) bool {
|
||||
}
|
||||
|
||||
func getFileReaders(
|
||||
configs []*config, logger log.Logger, service dashboards.DashboardProvisioningService, store utils.DashboardStore,
|
||||
configs []*config,
|
||||
logger log.Logger,
|
||||
service dashboards.DashboardProvisioningService,
|
||||
store utils.DashboardStore,
|
||||
folderService folder.Service,
|
||||
) ([]*FileReader, error) {
|
||||
var readers []*FileReader
|
||||
|
||||
for _, config := range configs {
|
||||
switch config.Type {
|
||||
case "file":
|
||||
fileReader, err := NewDashboardFileReader(config, logger.New("type", config.Type, "name", config.Name), service, store)
|
||||
fileReader, err := NewDashboardFileReader(
|
||||
config,
|
||||
logger.New("type", config.Type, "name", config.Name),
|
||||
service,
|
||||
store,
|
||||
folderService,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create file reader for config %v: %w", config.Name, err)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning/utils"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@@ -34,6 +35,7 @@ type FileReader struct {
|
||||
dashboardProvisioningService dashboards.DashboardProvisioningService
|
||||
dashboardStore utils.DashboardStore
|
||||
FoldersFromFilesStructure bool
|
||||
folderService folder.Service
|
||||
|
||||
mux sync.RWMutex
|
||||
usageTracker *usageTracker
|
||||
@@ -41,7 +43,8 @@ type FileReader struct {
|
||||
}
|
||||
|
||||
// NewDashboardFileReader returns a new filereader based on `config`
|
||||
func NewDashboardFileReader(cfg *config, log log.Logger, service dashboards.DashboardProvisioningService, dashboardStore utils.DashboardStore) (*FileReader, error) {
|
||||
func NewDashboardFileReader(cfg *config, log log.Logger, service dashboards.DashboardProvisioningService,
|
||||
dashboardStore utils.DashboardStore, folderService folder.Service) (*FileReader, error) {
|
||||
var path string
|
||||
path, ok := cfg.Options["path"].(string)
|
||||
if !ok {
|
||||
@@ -64,6 +67,7 @@ func NewDashboardFileReader(cfg *config, log log.Logger, service dashboards.Dash
|
||||
log: log,
|
||||
dashboardProvisioningService: service,
|
||||
dashboardStore: dashboardStore,
|
||||
folderService: folderService,
|
||||
FoldersFromFilesStructure: foldersFromFilesStructure,
|
||||
usageTracker: newUsageTracker(),
|
||||
}, nil
|
||||
@@ -333,22 +337,23 @@ func (fr *FileReader) getOrCreateFolder(ctx context.Context, cfg *config, servic
|
||||
|
||||
// dashboard folder not found. create one.
|
||||
if errors.Is(err, dashboards.ErrDashboardNotFound) {
|
||||
dash := &dashboards.SaveDashboardDTO{}
|
||||
dash.Dashboard = dashboards.NewDashboardFolder(folderName)
|
||||
dash.Dashboard.IsFolder = true
|
||||
dash.Overwrite = true
|
||||
dash.OrgID = cfg.OrgID
|
||||
// set dashboard folderUid if given
|
||||
if cfg.FolderUID == accesscontrol.GeneralFolderUID {
|
||||
return 0, "", dashboards.ErrFolderInvalidUID
|
||||
}
|
||||
dash.Dashboard.SetUID(cfg.FolderUID)
|
||||
dbDash, err := service.SaveFolderForProvisionedDashboards(ctx, dash)
|
||||
|
||||
createCmd := &folder.CreateFolderCommand{
|
||||
OrgID: cfg.OrgID,
|
||||
UID: cfg.FolderUID,
|
||||
Title: folderName,
|
||||
}
|
||||
|
||||
f, err := service.SaveFolderForProvisionedDashboards(ctx, createCmd)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
return dbDash.ID, dbDash.UID, nil
|
||||
// nolint:staticcheck
|
||||
return f.ID, f.UID, nil
|
||||
}
|
||||
|
||||
if !result.IsFolder {
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestProvisionedSymlinkedFolder(t *testing.T) {
|
||||
Options: map[string]any{"path": symlinkedFolder},
|
||||
}
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil)
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Error("expected err to be nil")
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
@@ -41,7 +42,7 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
|
||||
t.Run("using path parameter", func(t *testing.T) {
|
||||
cfg := setup()
|
||||
cfg.Options["path"] = defaultDashboards
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil)
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, reader.Path, "")
|
||||
})
|
||||
@@ -49,7 +50,7 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
|
||||
t.Run("using folder as options", func(t *testing.T) {
|
||||
cfg := setup()
|
||||
cfg.Options["folder"] = defaultDashboards
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil)
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, reader.Path, "")
|
||||
})
|
||||
@@ -58,7 +59,7 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
|
||||
cfg := setup()
|
||||
cfg.Options["path"] = foldersFromFilesStructure
|
||||
cfg.Options["foldersFromFilesStructure"] = true
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil)
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, reader.Path, "")
|
||||
})
|
||||
@@ -71,7 +72,7 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
|
||||
}
|
||||
|
||||
cfg.Options["folder"] = fullPath
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil)
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, reader.Path, fullPath)
|
||||
@@ -81,7 +82,7 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
|
||||
t.Run("using relative path", func(t *testing.T) {
|
||||
cfg := setup()
|
||||
cfg.Options["folder"] = defaultDashboards
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil)
|
||||
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resolvedPath := reader.resolvedPath()
|
||||
@@ -113,10 +114,10 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
cfg.Folder = "Team A"
|
||||
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(nil, nil).Once()
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{ID: 1}, nil).Once()
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{}, nil).Once()
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{ID: 2}, nil).Times(2)
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -136,7 +137,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
inserted++
|
||||
})
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -173,7 +174,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(provisionedDashboard, nil).Once()
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -201,7 +202,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(provisionedDashboard, nil).Once()
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Once()
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -236,7 +237,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(provisionedDashboard, nil).Once()
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -264,7 +265,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(provisionedDashboard, nil).Once()
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Once()
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -279,7 +280,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(nil, nil).Once()
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Once()
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -293,10 +294,10 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
cfg.Options["foldersFromFilesStructure"] = true
|
||||
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(nil, nil).Once()
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(2)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{}, nil).Times(2)
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(3)
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -313,7 +314,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
Folder: "",
|
||||
}
|
||||
|
||||
_, err := NewDashboardFileReader(cfg, logger, nil, nil)
|
||||
_, err := NewDashboardFileReader(cfg, logger, nil, nil, nil)
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
@@ -321,7 +322,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
setup()
|
||||
cfg.Options["path"] = brokenDashboards
|
||||
|
||||
_, err := NewDashboardFileReader(cfg, logger, nil, nil)
|
||||
_, err := NewDashboardFileReader(cfg, logger, nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
@@ -331,17 +332,17 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
cfg2 := &config{Name: "2", Type: "file", OrgID: 1, Folder: "f2", Options: map[string]any{"path": containingID}}
|
||||
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, mock.AnythingOfType("string")).Return(nil, nil).Times(2)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(2)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{}, nil).Times(2)
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(2)
|
||||
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore)
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, nil)
|
||||
reader1.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
err = reader1.walkDisk(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore)
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
|
||||
reader2.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -361,7 +362,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
"folder": defaultDashboards,
|
||||
},
|
||||
}
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, nil)
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg.Folder)
|
||||
@@ -379,9 +380,9 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
"folder": defaultDashboards,
|
||||
},
|
||||
}
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{ID: 1}, nil).Once()
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{}, nil).Once()
|
||||
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg.Folder)
|
||||
@@ -401,7 +402,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg.Folder)
|
||||
@@ -456,7 +457,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
|
||||
cfg.DisableDeletion = true
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
|
||||
@@ -471,7 +472,7 @@ func TestDashboardFileReader(t *testing.T) {
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Once()
|
||||
fakeService.On("DeleteProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
|
||||
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,9 +35,9 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
const folderName = "duplicates-validator-folder"
|
||||
|
||||
fakeStore := &fakeDashboardStore{}
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(6)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{}, nil).Times(6)
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, mock.AnythingOfType("string")).Return([]*dashboards.DashboardProvisioning{}, nil).Times(4)
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(5)
|
||||
_, folderUID, err := r.getOrCreateFolder(context.Background(), cfg, fakeService, folderName)
|
||||
@@ -53,11 +54,11 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
Options: map[string]any{"path": dashboardContainingUID},
|
||||
}
|
||||
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore)
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, nil)
|
||||
reader1.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore)
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
|
||||
reader2.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -90,7 +91,7 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
const folderName = "duplicates-validator-folder"
|
||||
|
||||
fakeStore := &fakeDashboardStore{}
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
_, folderUID, err := r.getOrCreateFolder(context.Background(), cfg, fakeService, folderName)
|
||||
require.NoError(t, err)
|
||||
@@ -106,11 +107,11 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
Options: map[string]any{"path": dashboardContainingUID},
|
||||
}
|
||||
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore)
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, nil)
|
||||
reader1.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore)
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
|
||||
reader2.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -150,7 +151,7 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Duplicates validator should restrict write access only for readers with duplicates", func(t *testing.T) {
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(5)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{}, nil).Times(5)
|
||||
fakeService.On("GetProvisionedDashboardData", mock.Anything, mock.AnythingOfType("string")).Return([]*dashboards.DashboardProvisioning{}, nil).Times(3)
|
||||
fakeService.On("SaveProvisionedDashboard", mock.Anything, mock.Anything, mock.Anything).Return(&dashboards.Dashboard{}, nil).Times(5)
|
||||
fakeStore := &fakeDashboardStore{}
|
||||
@@ -167,15 +168,15 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
Name: "third", Type: "file", OrgID: 2, Folder: "duplicates-validator-folder",
|
||||
Options: map[string]any{"path": twoDashboardsWithUID},
|
||||
}
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore)
|
||||
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, nil)
|
||||
reader1.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore)
|
||||
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
|
||||
reader2.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
reader3, err := NewDashboardFileReader(cfg3, logger, nil, fakeStore)
|
||||
reader3, err := NewDashboardFileReader(cfg3, logger, nil, fakeStore, nil)
|
||||
reader3.dashboardProvisioningService = fakeService
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -192,7 +193,7 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
|
||||
duplicates := duplicateValidator.getDuplicates()
|
||||
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore)
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
_, folderUID, err := r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg1.Folder)
|
||||
require.NoError(t, err)
|
||||
@@ -209,7 +210,7 @@ func TestDuplicatesValidator(t *testing.T) {
|
||||
sort.Strings(titleUsageReaders)
|
||||
require.Equal(t, []string{"first"}, titleUsageReaders)
|
||||
|
||||
r, err = NewDashboardFileReader(cfg3, logger, nil, fakeStore)
|
||||
r, err = NewDashboardFileReader(cfg3, logger, nil, fakeStore, nil)
|
||||
require.NoError(t, err)
|
||||
_, folderUID, err = r.getOrCreateFolder(context.Background(), cfg3, fakeService, cfg3.Folder)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -75,6 +75,7 @@ func ProvideService(
|
||||
secretService: secrectService,
|
||||
log: log.New("provisioning"),
|
||||
orgService: orgService,
|
||||
folderService: folderService,
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
@@ -145,6 +146,7 @@ type ProvisioningServiceImpl struct {
|
||||
searchService searchV2.SearchService
|
||||
quotaService quota.Service
|
||||
secretService secrets.Service
|
||||
folderService folder.Service
|
||||
}
|
||||
|
||||
func (ps *ProvisioningServiceImpl) RunInitProvisioners(ctx context.Context) error {
|
||||
@@ -239,7 +241,7 @@ func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) e
|
||||
|
||||
func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error {
|
||||
dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards")
|
||||
dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.orgService, ps.dashboardService)
|
||||
dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.orgService, ps.dashboardService, ps.folderService)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%v: %w", "Failed to create provisioner", err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning/utils"
|
||||
@@ -95,7 +96,7 @@ func setup() *serviceTestStruct {
|
||||
}
|
||||
|
||||
serviceTest.service = newProvisioningServiceImpl(
|
||||
func(context.Context, string, dashboardstore.DashboardProvisioningService, org.Service, utils.DashboardStore) (dashboards.DashboardProvisioner, error) {
|
||||
func(context.Context, string, dashboardstore.DashboardProvisioningService, org.Service, utils.DashboardStore, folder.Service) (dashboards.DashboardProvisioner, error) {
|
||||
return serviceTest.mock, nil
|
||||
},
|
||||
nil,
|
||||
|
||||
Reference in New Issue
Block a user