Provisioing: Update provisioned folder with a manager identity (#110988)
This commit is contained in:
@@ -6,7 +6,8 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
folderV1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@@ -57,8 +58,17 @@ func New(ctx context.Context, configDirectory string, provisioner dashboards.Das
|
||||
return nil, fmt.Errorf("%v: %w", "Failed to initialize file readers", err)
|
||||
}
|
||||
|
||||
if dual != nil && !dual.ShouldManage(dashboard.DashboardResourceInfo.GroupResource()) {
|
||||
dual = nil // not actively managed
|
||||
if dual != nil {
|
||||
foldersInUnified, _ := dual.ReadFromUnified(context.Background(), folderV1.FolderResourceInfo.GroupResource())
|
||||
if foldersInUnified {
|
||||
for _, reader := range fileReaders {
|
||||
reader.foldersInUnified = true
|
||||
}
|
||||
}
|
||||
|
||||
if !dual.ShouldManage(dashboardV1.DashboardResourceInfo.GroupResource()) {
|
||||
dual = nil // not actively managed
|
||||
}
|
||||
}
|
||||
|
||||
d := &Provisioner{
|
||||
@@ -78,7 +88,7 @@ func New(ctx context.Context, configDirectory string, provisioner dashboards.Das
|
||||
func (provider *Provisioner) Provision(ctx context.Context) error {
|
||||
// skip provisioning during migrations to prevent multi-replica instances from crashing when another replica is migrating
|
||||
if provider.dual != nil {
|
||||
status, _ := provider.dual.Status(context.Background(), dashboard.DashboardResourceInfo.GroupResource())
|
||||
status, _ := provider.dual.Status(context.Background(), dashboardV1.DashboardResourceInfo.GroupResource())
|
||||
if status.Migrating > 0 {
|
||||
provider.log.Info("dashboard migrations are running, skipping provisioning", "elapsed", time.Since(time.UnixMilli(status.Migrating)))
|
||||
return nil
|
||||
|
||||
@@ -40,6 +40,7 @@ type FileReader struct {
|
||||
dashboardStore utils.DashboardStore
|
||||
FoldersFromFilesStructure bool
|
||||
folderService folder.Service
|
||||
foldersInUnified bool
|
||||
|
||||
mux sync.RWMutex
|
||||
usageTracker *usageTracker
|
||||
@@ -382,6 +383,14 @@ func (fr *FileReader) getOrCreateFolder(ctx context.Context, cfg *config, servic
|
||||
return 0, "", dashboards.ErrFolderInvalidUID
|
||||
}
|
||||
|
||||
// When we expect folders in unified storage, they should have a manager indicated
|
||||
if err == nil && result != nil && result.ManagedBy == "" && fr.foldersInUnified {
|
||||
result, err = service.UpdateFolderWithManagedByAnnotation(ctx, result, fr.Cfg.Name)
|
||||
if err != nil {
|
||||
return 0, "", fmt.Errorf("unable to update provisioned folder")
|
||||
}
|
||||
}
|
||||
|
||||
// dashboard folder not found. create one.
|
||||
if errors.Is(err, dashboards.ErrFolderNotFound) {
|
||||
createCmd := &folder.CreateFolderCommand{
|
||||
|
||||
@@ -145,7 +145,7 @@ func TestIntegrationDashboardFileReader(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(&folder.Folder{ID: 1}, nil).Once()
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything, configName).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, folderSvc)
|
||||
reader.dashboardProvisioningService = fakeService
|
||||
@@ -324,7 +324,7 @@ func TestIntegrationDashboardFileReader(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(&folder.Folder{}, nil).Times(2)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything, configName).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, folderSvc)
|
||||
@@ -362,7 +362,7 @@ func TestIntegrationDashboardFileReader(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(&folder.Folder{}, nil).Times(2)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, 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, folderSvc)
|
||||
@@ -410,7 +410,7 @@ func TestIntegrationDashboardFileReader(t *testing.T) {
|
||||
"folder": defaultDashboards,
|
||||
},
|
||||
}
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything).Return(&folder.Folder{ID: 1}, nil).Once()
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, mock.Anything, cfg.Name).Return(&folder.Folder{ID: 1}, nil).Once()
|
||||
|
||||
r, err := NewDashboardFileReader(cfg, logger, nil, fakeStore, folderSvc)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestIntegrationDuplicatesValidator(t *testing.T) {
|
||||
fakeStore := &fakeDashboardStore{}
|
||||
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("SaveFolderForProvisionedDashboards", mock.Anything, 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(ctx, cfg, fakeService, folderName)
|
||||
@@ -183,7 +183,7 @@ func TestIntegrationDuplicatesValidator(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(&folder.Folder{}, nil).Times(5)
|
||||
fakeService.On("SaveFolderForProvisionedDashboards", mock.Anything, 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{}
|
||||
|
||||
@@ -88,6 +88,7 @@ func ProvideService(
|
||||
resourcePermissions: resourcePermissions,
|
||||
tracer: tracer,
|
||||
migratePrometheusType: promTypeMigrationProvider.Run,
|
||||
dual: dual,
|
||||
}
|
||||
|
||||
if err := s.setDashboardProvisioner(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user