mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard tags: add dashboard_uid and org_id (#98500)
This commit is contained in:
parent
17ed25e101
commit
7ab2539449
@ -20,6 +20,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/services/star"
|
||||
@ -41,9 +42,11 @@ type dashboardStore struct {
|
||||
|
||||
// SQL bean helper to save tags
|
||||
type dashboardTag struct {
|
||||
Id int64
|
||||
DashboardId int64
|
||||
Term string
|
||||
Id int64
|
||||
OrgID int64 `xorm:"org_id"`
|
||||
DashboardId int64
|
||||
DashboardUID string `xorm:"dashboard_uid"`
|
||||
Term string
|
||||
}
|
||||
|
||||
// DashboardStore implements the Store interface
|
||||
@ -57,6 +60,13 @@ func ProvideDashboardStore(sqlStore db.DB, cfg *setting.Cfg, features featuremgm
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fill out dashboard_uid and org_id for dashboard_tags
|
||||
// need to run this at startup in case any downgrade happened after the initial migration
|
||||
err = migrations.RunDashboardTagMigrations(sqlStore.GetEngine().NewSession(), sqlStore.GetDialect().DriverName())
|
||||
if err != nil {
|
||||
s.log.Error("Failed to run dashboard_tag migrations", "err", err)
|
||||
}
|
||||
|
||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
||||
TargetSrv: dashboards.QuotaTargetSrv,
|
||||
DefaultLimits: defaultLimits,
|
||||
@ -438,7 +448,7 @@ func saveDashboard(sess *db.Session, cmd *dashboards.SaveDashboardCommand, emitE
|
||||
}
|
||||
|
||||
// delete existing tags
|
||||
if _, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_id=?", dash.ID); err != nil {
|
||||
if _, err = sess.Exec("DELETE FROM dashboard_tag WHERE dashboard_uid=? AND org_id=?", dash.UID, dash.OrgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -446,7 +456,7 @@ func saveDashboard(sess *db.Session, cmd *dashboards.SaveDashboardCommand, emitE
|
||||
tags := dash.GetTags()
|
||||
if len(tags) > 0 {
|
||||
for _, tag := range tags {
|
||||
if _, err := sess.Insert(dashboardTag{DashboardId: dash.ID, Term: tag}); err != nil {
|
||||
if _, err := sess.Insert(dashboardTag{DashboardId: dash.ID, Term: tag, OrgID: dash.OrgID, DashboardUID: dash.UID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -604,7 +614,7 @@ func (d *dashboardStore) deleteDashboard(cmd *dashboards.DeleteDashboardCommand,
|
||||
}
|
||||
|
||||
sqlStatements := []statement{
|
||||
{SQL: "DELETE FROM dashboard_tag WHERE dashboard_id = ? ", args: []any{dashboard.ID}},
|
||||
{SQL: "DELETE FROM dashboard_tag WHERE dashboard_uid = ? AND org_id = ?", args: []any{dashboard.UID, dashboard.OrgID}},
|
||||
{SQL: "DELETE FROM star WHERE dashboard_id = ? ", args: []any{dashboard.ID}},
|
||||
{SQL: "DELETE FROM dashboard WHERE id = ?", args: []any{dashboard.ID}},
|
||||
{SQL: "DELETE FROM playlist_item WHERE type = 'dashboard_by_id' AND value = ?", args: []any{dashboard.ID}},
|
||||
@ -935,8 +945,8 @@ func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards
|
||||
COUNT(*) as count,
|
||||
term
|
||||
FROM dashboard
|
||||
INNER JOIN dashboard_tag on dashboard_tag.dashboard_id = dashboard.id
|
||||
WHERE dashboard.org_id=?
|
||||
INNER JOIN dashboard_tag on dashboard_tag.dashboard_uid = dashboard.uid
|
||||
WHERE dashboard_tag.org_id=?
|
||||
GROUP BY term
|
||||
ORDER BY term`
|
||||
|
||||
|
@ -213,15 +213,31 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
|
||||
assert.Equal(t, len(queryResult), 2)
|
||||
})
|
||||
|
||||
t.Run("Should be able to delete dashboard", func(t *testing.T) {
|
||||
t.Run("Should be able to delete dashboard and associated tags", func(t *testing.T) {
|
||||
setup()
|
||||
dash := insertTestDashboard(t, dashboardStore, "delete me", 1, 0, "", false, "delete this")
|
||||
|
||||
err := dashboardStore.DeleteDashboard(context.Background(), &dashboards.DeleteDashboardCommand{
|
||||
tags, err := dashboardStore.GetDashboardTags(context.Background(), &dashboards.GetDashboardTagsQuery{OrgID: 1})
|
||||
require.NoError(t, err)
|
||||
terms := make([]string, len(tags))
|
||||
for i, tag := range tags {
|
||||
terms[i] = tag.Term
|
||||
}
|
||||
require.Contains(t, terms, "delete this")
|
||||
|
||||
err = dashboardStore.DeleteDashboard(context.Background(), &dashboards.DeleteDashboardCommand{
|
||||
ID: dash.ID,
|
||||
OrgID: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tags, err = dashboardStore.GetDashboardTags(context.Background(), &dashboards.GetDashboardTagsQuery{OrgID: 1})
|
||||
require.NoError(t, err)
|
||||
terms = make([]string, len(tags))
|
||||
for i, tag := range tags {
|
||||
terms[i] = tag.Term
|
||||
}
|
||||
require.NotContains(t, terms, "delete this")
|
||||
})
|
||||
|
||||
t.Run("Should be able to create dashboard", func(t *testing.T) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func addDashboardMigration(mg *Migrator) {
|
||||
@ -244,4 +247,56 @@ func addDashboardMigration(mg *Migrator) {
|
||||
Cols: []string{"deleted"},
|
||||
Type: IndexType,
|
||||
}))
|
||||
|
||||
mg.AddMigration("Add column dashboard_uid in dashboard_tag", NewAddColumnMigration(dashboardTagV1, &Column{
|
||||
Name: "dashboard_uid", Type: DB_NVarchar, Length: 40, Nullable: true,
|
||||
}))
|
||||
mg.AddMigration("Add column org_id in dashboard_tag", NewAddColumnMigration(dashboardTagV1, &Column{
|
||||
Name: "org_id", Type: DB_BigInt, Nullable: true, Default: "1",
|
||||
}))
|
||||
|
||||
mg.AddMigration("Add missing dashboard_uid and org_id to dashboard_tag", &FillDashbordUIDAndOrgIDMigration{})
|
||||
}
|
||||
|
||||
type FillDashbordUIDAndOrgIDMigration struct {
|
||||
MigrationBase
|
||||
}
|
||||
|
||||
func (m *FillDashbordUIDAndOrgIDMigration) SQL(dialect Dialect) string {
|
||||
return "code migration"
|
||||
}
|
||||
|
||||
func (m *FillDashbordUIDAndOrgIDMigration) Exec(sess *xorm.Session, mg *Migrator) error {
|
||||
return RunDashboardTagMigrations(sess, mg.Dialect.DriverName())
|
||||
}
|
||||
|
||||
func RunDashboardTagMigrations(sess *xorm.Session, driverName string) error {
|
||||
// sqlite
|
||||
sql := `UPDATE dashboard_tag
|
||||
SET
|
||||
dashboard_uid = (SELECT uid FROM dashboard WHERE dashboard.id = dashboard_tag.dashboard_id),
|
||||
org_id = (SELECT org_id FROM dashboard WHERE dashboard.id = dashboard_tag.dashboard_id)
|
||||
WHERE
|
||||
(dashboard_uid IS NULL OR org_id IS NULL)
|
||||
AND EXISTS (SELECT 1 FROM dashboard WHERE dashboard.id = dashboard_tag.dashboard_id);`
|
||||
if driverName == Postgres {
|
||||
sql = `UPDATE dashboard_tag
|
||||
SET dashboard_uid = dashboard.uid,
|
||||
org_id = dashboard.org_id
|
||||
FROM dashboard
|
||||
WHERE dashboard_tag.dashboard_id = dashboard.id
|
||||
AND (dashboard_tag.dashboard_uid IS NULL OR dashboard_tag.org_id IS NULL);`
|
||||
} else if driverName == MySQL {
|
||||
sql = `UPDATE dashboard_tag
|
||||
LEFT JOIN dashboard ON dashboard_tag.dashboard_id = dashboard.id
|
||||
SET dashboard_tag.dashboard_uid = dashboard.uid,
|
||||
dashboard_tag.org_id = dashboard.org_id
|
||||
WHERE dashboard_tag.dashboard_uid IS NULL OR dashboard_tag.org_id IS NULL;`
|
||||
}
|
||||
|
||||
if _, err := sess.Exec(sql); err != nil {
|
||||
return fmt.Errorf("failed to set dashboard_uid and org_id in dashboard_tag: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user