From 6f02d193f61e0f7859b7620a3eeac77bb7b74ff0 Mon Sep 17 00:00:00 2001 From: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:55:29 +0200 Subject: [PATCH] Provisioning: Fix failure to save dashboard (#81694) --- pkg/services/dashboards/dashboard.go | 3 ++ pkg/services/dashboards/database/database.go | 8 +++--- .../dashboards/database/database_test.go | 28 +++++++++++++++++-- pkg/services/dashboards/models.go | 2 +- .../provisioning/dashboards/file_reader.go | 20 +++++++++---- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/pkg/services/dashboards/dashboard.go b/pkg/services/dashboards/dashboard.go index ff13b96f64e..8e2b8223325 100644 --- a/pkg/services/dashboards/dashboard.go +++ b/pkg/services/dashboards/dashboard.go @@ -17,6 +17,9 @@ type DashboardService interface { BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*SaveDashboardCommand, error) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error FindDashboards(ctx context.Context, query *FindPersistedDashboardsQuery) ([]DashboardSearchProjection, error) + // GetDashboard fetches a dashboard. + // To fetch a dashboard under root by title should set the folder UID to point to an empty string + // eg. util.Pointer("") GetDashboard(ctx context.Context, query *GetDashboardQuery) (*Dashboard, error) GetDashboards(ctx context.Context, query *GetDashboardsQuery) ([]*Dashboard, error) GetDashboardTags(ctx context.Context, query *GetDashboardTagsQuery) ([]*DashboardTagCloudItem, error) diff --git a/pkg/services/dashboards/database/database.go b/pkg/services/dashboards/database/database.go index 80beba5921a..2172a3fa080 100644 --- a/pkg/services/dashboards/database/database.go +++ b/pkg/services/dashboards/database/database.go @@ -827,7 +827,7 @@ func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.Get err := d.store.WithDbSession(ctx, func(sess *db.Session) error { metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc() // nolint:staticcheck - if query.ID == 0 && len(query.UID) == 0 && (query.Title == nil || (query.FolderID == nil && query.FolderUID == "")) { + if query.ID == 0 && len(query.UID) == 0 && (query.Title == nil || (query.FolderID == nil && query.FolderUID == nil)) { return dashboards.ErrDashboardIdentifierNotSet } @@ -838,8 +838,8 @@ func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.Get mustCols = append(mustCols, "title") } - if query.FolderUID != "" { - dashboard.FolderUID = query.FolderUID + if query.FolderUID != nil { + dashboard.FolderUID = *query.FolderUID mustCols = append(mustCols, "folder_uid") } else if query.FolderID != nil { // nolint:staticcheck // nolint:staticcheck @@ -848,7 +848,7 @@ func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.Get metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc() } - has, err := sess.MustCols(mustCols...).Get(&dashboard) + has, err := sess.MustCols(mustCols...).Nullable("folder_uid").Get(&dashboard) if err != nil { return err } else if !has { diff --git a/pkg/services/dashboards/database/database_test.go b/pkg/services/dashboards/database/database_test.go index 906c9776f5f..0aacdf667ba 100644 --- a/pkg/services/dashboards/database/database_test.go +++ b/pkg/services/dashboards/database/database_test.go @@ -104,11 +104,35 @@ func TestIntegrationDashboardDataAccess(t *testing.T) { require.ErrorIs(t, err, dashboards.ErrDashboardIdentifierNotSet) }) + t.Run("Should be able to get root dashboard by title", func(t *testing.T) { + setup() + query := dashboards.GetDashboardQuery{ + Title: util.Pointer("test dash 67"), + FolderUID: util.Pointer(""), + OrgID: 1, + } + + _, err := dashboardStore.GetDashboard(context.Background(), &query) + require.Error(t, err) + }) + + t.Run("Should be able to get dashboard by title and folderID", func(t *testing.T) { + setup() + query := dashboards.GetDashboardQuery{ + Title: util.Pointer("test dash 23"), + FolderID: &savedDash.ID, + OrgID: 1, + } + + _, err := dashboardStore.GetDashboard(context.Background(), &query) + require.Error(t, err) + }) + t.Run("Should be able to get dashboard by title and folderUID", func(t *testing.T) { setup() query := dashboards.GetDashboardQuery{ Title: util.Pointer("test dash 23"), - FolderUID: savedFolder.UID, + FolderUID: util.Pointer(savedFolder.UID), OrgID: 1, } queryResult, err := dashboardStore.GetDashboard(context.Background(), &query) @@ -160,7 +184,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) { setup() query := dashboards.GetDashboardQuery{ Title: util.Pointer("test dash 23"), - FolderUID: "", + FolderUID: util.Pointer(""), OrgID: 1, } diff --git a/pkg/services/dashboards/models.go b/pkg/services/dashboards/models.go index 7f23ac5a1e5..e3b4cf4bca1 100644 --- a/pkg/services/dashboards/models.go +++ b/pkg/services/dashboards/models.go @@ -252,7 +252,7 @@ type GetDashboardQuery struct { Title *string // Deprecated: use FolderUID instead FolderID *int64 - FolderUID string + FolderUID *string OrgID int64 } diff --git a/pkg/services/provisioning/dashboards/file_reader.go b/pkg/services/provisioning/dashboards/file_reader.go index 2e88142f3e2..e80aefe1a9d 100644 --- a/pkg/services/provisioning/dashboards/file_reader.go +++ b/pkg/services/provisioning/dashboards/file_reader.go @@ -254,18 +254,26 @@ func (fr *FileReader) saveDashboard(ctx context.Context, path string, folderID i // fix empty folder_uid from already provisioned dashboards if upToDate && folderUID != "" { + // search for root dashboard with the specified uid or title d, err := fr.dashboardStore.GetDashboard( ctx, &dashboards.GetDashboardQuery{ - OrgID: jsonFile.dashboard.OrgID, - UID: jsonFile.dashboard.Dashboard.UID, + OrgID: jsonFile.dashboard.OrgID, + UID: jsonFile.dashboard.Dashboard.UID, + Title: &jsonFile.dashboard.Dashboard.Title, + FolderUID: util.Pointer(""), }, ) if err != nil { - return provisioningMetadata, err - } - if d.FolderUID != folderUID { - upToDate = false + // if no problematic entry is found it's safe to ignore + if !errors.Is(err, dashboards.ErrDashboardNotFound) { + return provisioningMetadata, err + } + } else { + // inconsistency is detected so force updating the dashboard + if d.FolderUID != folderUID { + upToDate = false + } } }