Unistore: refactor provisioning to work with folder service (#99473)

This commit is contained in:
maicon
2025-01-29 05:19:38 +02:00
committed by GitHub
parent 6908f91428
commit 20f02ec12f
13 changed files with 180 additions and 77 deletions
@@ -240,9 +240,9 @@ func (s *Service) getFolderByTitleFromApiServer(ctx context.Context, orgID int64
Key: folderkey,
Fields: []*resource.Requirement{
{
Key: resource.SEARCH_FIELD_TITLE,
Key: resource.SEARCH_FIELD_TITLE_SORT,
Operator: string(selection.In),
Values: []string{title},
Values: []string{strings.ToLower(title)},
},
},
Labels: []*resource.Requirement{},
@@ -567,7 +567,7 @@ func (r resourceClientMock) Search(ctx context.Context, in *resource.ResourceSea
}
if len(in.Options.Fields) > 0 &&
in.Options.Fields[0].Key == resource.SEARCH_FIELD_TITLE &&
in.Options.Fields[0].Key == resource.SEARCH_FIELD_TITLE_SORT &&
in.Options.Fields[0].Operator == "in" &&
len(in.Options.Fields[0].Values) > 0 &&
in.Options.Fields[0].Values[0] == "foo" {
@@ -45,7 +45,8 @@ func (prov *defaultAlertRuleProvisioner) Provision(ctx context.Context,
files []*AlertingFile) error {
for _, file := range files {
for _, group := range file.Groups {
u := provisionerUser(group.OrgID)
ctx, u := identity.WithServiceIdentitiy(ctx, group.OrgID)
folderUID, err := prov.getOrCreateFolderFullpath(ctx, group.FolderFullpath, group.OrgID)
if err != nil {
prov.logger.Error("failed to get or create folder", "folder", group.FolderFullpath, "org", group.OrgID, "err", err)
@@ -120,11 +121,13 @@ func (prov *defaultAlertRuleProvisioner) getOrCreateFolderFullpath(
func (prov *defaultAlertRuleProvisioner) getOrCreateFolderByTitle(
ctx context.Context, folderName string, orgID int64, parentUID *string) (string, error) {
ctx, user := identity.WithServiceIdentitiy(ctx, orgID)
cmd := &folder.GetFolderQuery{
Title: &folderName,
ParentUID: parentUID,
OrgID: orgID,
SignedInUser: provisionerUser(orgID),
SignedInUser: user,
}
cmdResult, err := prov.folderService.Get(ctx, cmd)
@@ -11,6 +11,7 @@ import (
"sync"
"time"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
@@ -147,6 +148,8 @@ func (fr *FileReader) isDatabaseAccessRestricted() bool {
// storeDashboardsInFolder saves dashboards from the filesystem on disk to the folder from config
func (fr *FileReader) storeDashboardsInFolder(ctx context.Context, filesFoundOnDisk map[string]os.FileInfo,
dashboardRefs map[string]*dashboards.DashboardProvisioning, usageTracker *usageTracker) error {
ctx, _ = identity.WithServiceIdentitiy(ctx, fr.Cfg.OrgID)
folderID, folderUID, err := fr.getOrCreateFolder(ctx, fr.Cfg, fr.dashboardProvisioningService, fr.Cfg.Folder)
if err != nil && !errors.Is(err, ErrFolderNameMissing) {
return fmt.Errorf("%w with name %q: %w", ErrGetOrCreateFolder, fr.Cfg.Folder, err)
@@ -177,6 +180,7 @@ func (fr *FileReader) storeDashboardsInFoldersFromFileStructure(ctx context.Cont
folderName = filepath.Base(dashboardsFolder)
}
ctx, _ = identity.WithServiceIdentitiy(ctx, fr.Cfg.OrgID)
folderID, folderUID, err := fr.getOrCreateFolder(ctx, fr.Cfg, fr.dashboardProvisioningService, folderName)
if err != nil && !errors.Is(err, ErrFolderNameMissing) {
return fmt.Errorf("%w with name %q from file system structure: %w", ErrGetOrCreateFolder, folderName, err)
@@ -342,38 +346,42 @@ func (fr *FileReader) getOrCreateFolder(ctx context.Context, cfg *config, servic
return 0, "", ErrFolderNameMissing
}
// TODO use folder service instead
user, err := identity.GetRequester(ctx)
if err != nil {
return 0, "", err
}
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Provisioning).Inc()
cmd := &dashboards.GetDashboardQuery{
FolderID: util.Pointer(int64(0)), // nolint:staticcheck
OrgID: cfg.OrgID,
cmd := &folder.GetFolderQuery{
OrgID: cfg.OrgID,
SignedInUser: user,
}
if cfg.FolderUID != "" {
cmd.UID = cfg.FolderUID
cmd.UID = &cfg.FolderUID
} else {
// provisioning depends on unique names
//nolint:staticcheck
cmd.Title = &folderName
}
result, err := fr.dashboardStore.GetDashboard(ctx, cmd)
if err != nil && !errors.Is(err, dashboards.ErrDashboardNotFound) {
result, err := fr.folderService.Get(ctx, cmd)
if err != nil && !errors.Is(err, dashboards.ErrFolderNotFound) {
return 0, "", err
}
// dashboard folder not found. create one.
if errors.Is(err, dashboards.ErrDashboardNotFound) {
// set dashboard folderUid if given
if cfg.FolderUID == accesscontrol.GeneralFolderUID {
return 0, "", dashboards.ErrFolderInvalidUID
}
// do not allow the creation of folder with uid "general"
if result != nil && result.UID == accesscontrol.GeneralFolderUID {
return 0, "", dashboards.ErrFolderInvalidUID
}
// dashboard folder not found. create one.
if errors.Is(err, dashboards.ErrFolderNotFound) {
createCmd := &folder.CreateFolderCommand{
OrgID: cfg.OrgID,
UID: cfg.FolderUID,
Title: folderName,
OrgID: cfg.OrgID,
UID: cfg.FolderUID,
Title: folderName,
SignedInUser: user,
}
f, err := service.SaveFolderForProvisionedDashboards(ctx, createCmd)
@@ -385,10 +393,7 @@ func (fr *FileReader) getOrCreateFolder(ctx context.Context, cfg *config, servic
return f.ID, f.UID, nil
}
if !result.IsFolder {
return 0, "", fmt.Errorf("got invalid response. expected folder, found dashboard")
}
//nolint:staticcheck
return result.ID, result.UID, nil
}
@@ -12,9 +12,20 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
"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/supportbundles/supportbundlestest"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
"github.com/grafana/grafana/pkg/tests/testsuite"
"github.com/grafana/grafana/pkg/util"
)
@@ -28,6 +39,10 @@ const (
configName = "default"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
func TestCreatingNewDashboardFileReader(t *testing.T) {
setup := func() *config {
return &config{
@@ -107,6 +122,17 @@ func TestDashboardFileReader(t *testing.T) {
}
}
sql, cfgT := db.InitTestDBWithCfg(t)
features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
fStore := folderimpl.ProvideStore(sql)
tagService := tagimpl.ProvideService(sql)
dashStore, err := database.ProvideDashboardStore(sql, cfgT, features, tagService)
require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sql)
folderSvc := folderimpl.ProvideService(fStore, actest.FakeAccessControl{}, bus.ProvideBus(tracing.InitializeTracerForTest()),
dashStore, folderStore, nil, sql, featuremgmt.WithFeatures(),
supportbundlestest.NewFakeBundleService(), nil, cfgT, nil, tracing.InitializeTracerForTest())
t.Run("Reading dashboards from disk", func(t *testing.T) {
t.Run("Can read default dashboard", func(t *testing.T) {
setup()
@@ -116,8 +142,7 @@ func TestDashboardFileReader(t *testing.T) {
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(nil, nil).Once()
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{ID: 1}, 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, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -137,7 +162,7 @@ func TestDashboardFileReader(t *testing.T) {
inserted++
})
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -174,7 +199,7 @@ func TestDashboardFileReader(t *testing.T) {
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(provisionedDashboard, nil).Once()
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -202,7 +227,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, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -237,7 +262,7 @@ func TestDashboardFileReader(t *testing.T) {
fakeService.On("GetProvisionedDashboardData", mock.Anything, configName).Return(provisionedDashboard, nil).Once()
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -265,7 +290,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, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -280,7 +305,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, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -297,7 +322,7 @@ func TestDashboardFileReader(t *testing.T) {
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, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -314,7 +339,7 @@ func TestDashboardFileReader(t *testing.T) {
Folder: "",
}
_, err := NewDashboardFileReader(cfg, logger, nil, nil, nil)
_, err := NewDashboardFileReader(cfg, logger, nil, nil, folderSvc)
require.NotNil(t, err)
})
@@ -322,7 +347,7 @@ func TestDashboardFileReader(t *testing.T) {
setup()
cfg.Options["path"] = brokenDashboards
_, err := NewDashboardFileReader(cfg, logger, nil, nil, nil)
_, err := NewDashboardFileReader(cfg, logger, nil, nil, folderSvc)
require.NoError(t, err)
})
@@ -335,14 +360,14 @@ func TestDashboardFileReader(t *testing.T) {
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, nil)
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, folderSvc)
reader1.dashboardProvisioningService = fakeService
require.NoError(t, err)
err = reader1.walkDisk(context.Background())
require.NoError(t, err)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, folderSvc)
reader2.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -362,7 +387,7 @@ func TestDashboardFileReader(t *testing.T) {
"folder": defaultDashboards,
},
}
r, err := NewDashboardFileReader(cfg, logger, nil, nil, nil)
r, err := NewDashboardFileReader(cfg, logger, nil, nil, folderSvc)
require.NoError(t, err)
_, _, err = r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg.Folder)
@@ -382,10 +407,12 @@ func TestDashboardFileReader(t *testing.T) {
}
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{ID: 1}, nil).Once()
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
_, _, err = r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg.Folder)
ctx := context.Background()
ctx, _ = identity.WithServiceIdentitiy(ctx, 1)
_, _, err = r.getOrCreateFolder(ctx, cfg, fakeService, cfg.Folder)
require.NoError(t, err)
})
@@ -402,10 +429,12 @@ func TestDashboardFileReader(t *testing.T) {
},
}
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
_, _, err = r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg.Folder)
ctx := context.Background()
ctx, _ = identity.WithServiceIdentitiy(ctx, 1)
_, _, err = r.getOrCreateFolder(ctx, cfg, fakeService, cfg.Folder)
require.ErrorIs(t, err, dashboards.ErrFolderInvalidUID)
})
@@ -457,7 +486,7 @@ func TestDashboardFileReader(t *testing.T) {
cfg.DisableDeletion = true
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
reader.dashboardProvisioningService = fakeService
@@ -472,7 +501,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, nil)
reader, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
reader.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -8,9 +8,19 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
"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/supportbundles/supportbundlestest"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
)
const (
@@ -31,16 +41,30 @@ func TestDuplicatesValidator(t *testing.T) {
}
logger := log.New("test.logger")
sql, cfgT := db.InitTestDBWithCfg(t)
features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
fStore := folderimpl.ProvideStore(sql)
tagService := tagimpl.ProvideService(sql)
dashStore, err := database.ProvideDashboardStore(sql, cfgT, features, tagService)
require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sql)
folderSvc := folderimpl.ProvideService(fStore, actest.FakeAccessControl{}, bus.ProvideBus(tracing.InitializeTracerForTest()),
dashStore, folderStore, nil, sql, featuremgmt.WithFeatures(),
supportbundlestest.NewFakeBundleService(), nil, cfgT, nil, tracing.InitializeTracerForTest())
t.Run("Duplicates validator should collect info about duplicate UIDs and titles within folders", func(t *testing.T) {
const folderName = "duplicates-validator-folder"
ctx := context.Background()
ctx, _ = identity.WithServiceIdentitiy(ctx, 1)
fakeStore := &fakeDashboardStore{}
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
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)
_, folderUID, err := r.getOrCreateFolder(ctx, cfg, fakeService, folderName)
require.NoError(t, err)
identity := dashboardIdentity{folderUID: folderUID, title: "Grafana"}
@@ -54,11 +78,11 @@ func TestDuplicatesValidator(t *testing.T) {
Options: map[string]any{"path": dashboardContainingUID},
}
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, nil)
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, folderSvc)
reader1.dashboardProvisioningService = fakeService
require.NoError(t, err)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, folderSvc)
reader2.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -90,10 +114,13 @@ func TestDuplicatesValidator(t *testing.T) {
t.Run("Duplicates validator should not collect info about duplicate UIDs and titles within folders for different orgs", func(t *testing.T) {
const folderName = "duplicates-validator-folder"
ctx := context.Background()
ctx, _ = identity.WithServiceIdentitiy(ctx, 1)
fakeStore := &fakeDashboardStore{}
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
_, folderUID, err := r.getOrCreateFolder(context.Background(), cfg, fakeService, folderName)
_, folderUID, err := r.getOrCreateFolder(ctx, cfg, fakeService, folderName)
require.NoError(t, err)
identity := dashboardIdentity{folderUID: folderUID, title: "Grafana"}
@@ -107,11 +134,11 @@ func TestDuplicatesValidator(t *testing.T) {
Options: map[string]any{"path": dashboardContainingUID},
}
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, nil)
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, folderSvc)
reader1.dashboardProvisioningService = fakeService
require.NoError(t, err)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, folderSvc)
reader2.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -168,15 +195,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, nil)
reader1, err := NewDashboardFileReader(cfg1, logger, nil, fakeStore, folderSvc)
reader1.dashboardProvisioningService = fakeService
require.NoError(t, err)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, nil)
reader2, err := NewDashboardFileReader(cfg2, logger, nil, fakeStore, folderSvc)
reader2.dashboardProvisioningService = fakeService
require.NoError(t, err)
reader3, err := NewDashboardFileReader(cfg3, logger, nil, fakeStore, nil)
reader3, err := NewDashboardFileReader(cfg3, logger, nil, fakeStore, folderSvc)
reader3.dashboardProvisioningService = fakeService
require.NoError(t, err)
@@ -193,9 +220,12 @@ func TestDuplicatesValidator(t *testing.T) {
duplicates := duplicateValidator.getDuplicates()
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, nil)
ctx := context.Background()
ctx, _ = identity.WithServiceIdentitiy(ctx, 1)
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
_, folderUID, err := r.getOrCreateFolder(context.Background(), cfg, fakeService, cfg1.Folder)
_, folderUID, err := r.getOrCreateFolder(ctx, cfg, fakeService, cfg1.Folder)
require.NoError(t, err)
identity := dashboardIdentity{folderUID: folderUID, title: "Grafana"}
@@ -210,9 +240,9 @@ func TestDuplicatesValidator(t *testing.T) {
sort.Strings(titleUsageReaders)
require.Equal(t, []string{"first"}, titleUsageReaders)
r, err = NewDashboardFileReader(cfg3, logger, nil, fakeStore, nil)
r, err = NewDashboardFileReader(cfg3, logger, nil, fakeStore, folderSvc)
require.NoError(t, err)
_, folderUID, err = r.getOrCreateFolder(context.Background(), cfg3, fakeService, cfg3.Folder)
_, folderUID, err = r.getOrCreateFolder(ctx, cfg3, fakeService, cfg3.Folder)
require.NoError(t, err)
identity = dashboardIdentity{folderUID: folderUID, title: "Grafana"}
+14 -1
View File
@@ -164,6 +164,7 @@ type ProvisioningServiceImpl struct {
folderService folder.Service
resourcePermissions accesscontrol.ReceiverPermissionsService
tracer tracing.Tracer
onceInitProvisioners sync.Once
}
func (ps *ProvisioningServiceImpl) RunInitProvisioners(ctx context.Context) error {
@@ -189,7 +190,19 @@ func (ps *ProvisioningServiceImpl) RunInitProvisioners(ctx context.Context) erro
}
func (ps *ProvisioningServiceImpl) Run(ctx context.Context) error {
err := ps.ProvisionDashboards(ctx)
var err error
// run Init Provisioners only once
ps.onceInitProvisioners.Do(func() {
err = ps.RunInitProvisioners(ctx)
})
if err != nil {
// error already logged
return err
}
err = ps.ProvisionDashboards(ctx)
if err != nil {
ps.log.Error("Failed to provision dashboard", "error", err)
// Consider the allow list of errors for which running the provisioning service should not
+13 -2
View File
@@ -13,7 +13,11 @@ import (
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/pluginsintegration/pluginsettings"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
prov_alerting "github.com/grafana/grafana/pkg/services/provisioning/alerting"
"github.com/grafana/grafana/pkg/services/provisioning/dashboards"
"github.com/grafana/grafana/pkg/services/provisioning/datasources"
"github.com/grafana/grafana/pkg/services/provisioning/utils"
"github.com/grafana/grafana/pkg/services/searchV2"
)
@@ -159,10 +163,17 @@ func setup(t *testing.T) *serviceTestStruct {
serviceTest.dashboardProvisionerInstantiations++
return serviceTest.mock, nil
},
nil,
nil,
func(context.Context, string, datasources.BaseDataSourceService, datasources.CorrelationsStore, org.Service) error {
return nil
},
func(context.Context, string, pluginstore.Store, pluginsettings.Service, org.Service) error {
return nil
},
searchStub,
)
service.provisionAlerting = func(context.Context, prov_alerting.ProvisionerConfig) error {
return nil
}
serviceTest.service = service
require.NoError(t, err)