Annotations: Use dashboard uids instead of dashboard ids (#106676)

This commit is contained in:
Stephanie Hingtgen
2025-06-13 13:59:24 -05:00
committed by GitHub
parent 47f3073ab8
commit a8886ad5ec
20 changed files with 410 additions and 228 deletions
@@ -79,6 +79,7 @@ func (r *RepositoryImpl) Find(ctx context.Context, query *annotations.ItemQuery)
}
// Search without dashboard UID filter is expensive, so check without access control first
// nolint: staticcheck
if query.DashboardID == 0 && query.DashboardUID == "" {
// Return early if no annotations found, it's not necessary to perform expensive access control filtering
res, err := r.reader.Get(ctx, *query, &accesscontrol.AccessResources{
@@ -81,7 +81,7 @@ func TestIntegrationAnnotationListingWithRBAC(t *testing.T) {
}),
})
_ = testutil.CreateDashboard(t, sql, cfg, features, dashboards.SaveDashboardCommand{
dashboard2 := testutil.CreateDashboard(t, sql, cfg, features, dashboards.SaveDashboardCommand{
UserID: 1,
OrgID: 1,
IsFolder: false,
@@ -91,18 +91,20 @@ func TestIntegrationAnnotationListingWithRBAC(t *testing.T) {
})
dash1Annotation := &annotations.Item{
OrgID: 1,
DashboardID: 1,
Epoch: 10,
OrgID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard1.UID,
Epoch: 10,
}
err = repo.Save(context.Background(), dash1Annotation)
require.NoError(t, err)
dash2Annotation := &annotations.Item{
OrgID: 1,
DashboardID: 2,
Epoch: 10,
Tags: []string{"foo:bar"},
OrgID: 1,
DashboardID: 2, // nolint: staticcheck
DashboardUID: dashboard2.UID,
Epoch: 10,
Tags: []string{"foo:bar"},
}
err = repo.Save(context.Background(), dash2Annotation)
require.NoError(t, err)
@@ -292,10 +294,11 @@ func TestIntegrationAnnotationListingWithInheritedRBAC(t *testing.T) {
annotationTxt := fmt.Sprintf("annotation %d", i)
dash1Annotation := &annotations.Item{
OrgID: orgID,
DashboardID: dashboard.ID,
Epoch: 10,
Text: annotationTxt,
OrgID: orgID,
DashboardID: dashboard.ID, // nolint: staticcheck
DashboardUID: dashboard.UID,
Epoch: 10,
Text: annotationTxt,
}
err = store.Add(context.Background(), dash1Annotation)
require.NoError(t, err)
@@ -3,6 +3,7 @@ package annotationsimpl
import (
"context"
"errors"
"strconv"
"testing"
"time"
@@ -238,24 +239,27 @@ func createTestAnnotations(t *testing.T, store db.DB, expectedCount int, oldAnno
newAnnotationTags := make([]*annotationTag, 0, 2*expectedCount)
for i := 0; i < expectedCount; i++ {
a := &annotations.Item{
ID: int64(i + 1),
DashboardID: 1,
OrgID: 1,
UserID: 1,
PanelID: 1,
Text: "",
ID: int64(i + 1),
DashboardID: 1,
DashboardUID: "uid" + strconv.Itoa(i),
OrgID: 1,
UserID: 1,
PanelID: 1,
Text: "",
}
// mark every third as an API annotation
// that does not belong to a dashboard
if i%3 == 1 {
a.DashboardID = 0
a.DashboardID = 0 // nolint: staticcheck
a.DashboardUID = ""
}
// mark every third annotation as an alert annotation
if i%3 == 0 {
a.AlertID = 10
a.DashboardID = 2
a.DashboardID = 2 // nolint: staticcheck
a.DashboardUID = "dashboard2uid"
}
// create epoch as int annotations.go line 40
@@ -85,6 +85,7 @@ func (r *LokiHistorianStore) Get(ctx context.Context, query annotations.ItemQuer
// if the query is filtering on tags, but not on a specific dashboard, we shouldn't query loki
// since state history won't have tags for annotations
// nolint: staticcheck
if len(query.Tags) > 0 && query.DashboardID == 0 && query.DashboardUID == "" {
return make([]*annotations.ItemDTO, 0), nil
}
@@ -178,7 +179,7 @@ func (r *LokiHistorianStore) annotationsFromStream(stream historian.Stream, ac a
items = append(items, &annotations.ItemDTO{
AlertID: entry.RuleID,
DashboardID: ac.Dashboards[entry.DashboardUID],
DashboardID: ac.Dashboards[entry.DashboardUID], // nolint: staticcheck
DashboardUID: &entry.DashboardUID,
PanelID: entry.PanelID,
NewState: entry.Current,
@@ -280,8 +281,10 @@ func buildHistoryQuery(query *annotations.ItemQuery, dashboards map[string]int64
RuleUID: ruleUID,
}
// nolint: staticcheck
if historyQuery.DashboardUID == "" && query.DashboardID != 0 {
for uid, id := range dashboards {
// nolint: staticcheck
if query.DashboardID == id {
historyQuery.DashboardUID = uid
break
@@ -193,7 +193,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: dashboard1.ID,
DashboardID: dashboard1.ID, // nolint: staticcheck
From: start.UnixMilli(),
To: start.Add(time.Second * time.Duration(numTransitions+1)).UnixMilli(),
}
@@ -243,7 +243,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: dashboard1.ID,
DashboardID: dashboard1.ID, // nolint: staticcheck
From: start.Add(-2 * time.Second).UnixMilli(),
To: start.Add(-1 * time.Second).UnixMilli(),
}
@@ -273,7 +273,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: dashboard1.ID,
DashboardID: dashboard1.ID, // nolint: staticcheck
From: start.Add(-1 * time.Second).UnixMilli(), // should clamp to start
To: start.Add(1 * time.Second).UnixMilli(),
}
@@ -294,17 +294,17 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
fakeLokiClient.cfg.MaxQueryLength = oldMax
})
t.Run("should sort history by time", func(t *testing.T) {
t.Run("should sort history by time and be able to query by dashboard uid", func(t *testing.T) {
fakeLokiClient.rangeQueryRes = []historian.Stream{
historian.StatesToStream(ruleMetaFromRule(t, dashboardRules[dashboard1.UID][0]), transitions, map[string]string{}, log.NewNopLogger()),
historian.StatesToStream(ruleMetaFromRule(t, dashboardRules[dashboard1.UID][1]), transitions, map[string]string{}, log.NewNopLogger()),
}
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: dashboard1.ID,
From: start.UnixMilli(),
To: start.Add(time.Second * time.Duration(numTransitions+1)).UnixMilli(),
OrgID: 1,
DashboardUID: dashboard1.UID,
From: start.UnixMilli(),
To: start.Add(time.Second * time.Duration(numTransitions+1)).UnixMilli(),
}
res, err := store.Get(
context.Background(),
@@ -393,7 +393,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
expected := &annotations.ItemDTO{
AlertID: rule.ID,
DashboardID: dashboard1.ID,
DashboardID: dashboard1.ID, // nolint: staticcheck
DashboardUID: &dashboard1.UID,
PanelID: *rule.PanelID,
Time: transition.LastEvaluationTime.UnixMilli(),
@@ -433,6 +433,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
require.Len(t, items, numTransitions)
for _, item := range items {
// nolint: staticcheck
require.Equal(t, dashboard1.ID, item.DashboardID)
require.Equal(t, dashboard1.UID, *item.DashboardUID)
}
@@ -464,7 +465,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
for _, item := range items {
require.Zero(t, *item.DashboardUID)
require.Zero(t, item.DashboardID)
require.Zero(t, item.DashboardID) // nolint: staticcheck
}
})
})
@@ -553,7 +554,7 @@ func TestBuildHistoryQuery(t *testing.T) {
t.Run("should set dashboard UID from dashboard ID if query does not contain UID", func(t *testing.T) {
query := buildHistoryQuery(
&annotations.ItemQuery{
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
},
map[string]int64{
"dashboard-uid": 1,
@@ -566,7 +567,7 @@ func TestBuildHistoryQuery(t *testing.T) {
t.Run("should skip dashboard UID if missing from query and dashboard map", func(t *testing.T) {
query := buildHistoryQuery(
&annotations.ItemQuery{
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
},
map[string]int64{
"other-dashboard-uid": 2,
@@ -794,7 +795,7 @@ func compareAnnotationItem(t *testing.T, expected, actual *annotations.ItemDTO)
require.Equal(t, expected.PanelID, actual.PanelID)
}
if expected.DashboardUID != nil {
require.Equal(t, expected.DashboardID, actual.DashboardID)
require.Equal(t, expected.DashboardID, actual.DashboardID) // nolint: staticcheck
require.Equal(t, *expected.DashboardUID, *actual.DashboardUID)
}
require.Equal(t, expected.NewState, actual.NewState)
@@ -5,11 +5,11 @@ import (
"context"
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/grafana/grafana/pkg/services/annotations/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/apimachinery/identity"
@@ -46,6 +46,13 @@ type xormRepositoryImpl struct {
}
func NewXormStore(cfg *setting.Cfg, l log.Logger, db db.DB, tagService tag.Service) *xormRepositoryImpl {
// populate dashboard_uid at startup, to ensure safe downgrades & upgrades after
// the initial migration occurs
err := migrations.RunDashboardUIDMigrations(db.GetEngine().NewSession(), db.GetEngine().DriverName())
if err != nil {
l.Error("failed to populate dashboard_uid for annotations", "error", err)
}
return &xormRepositoryImpl{
cfg: cfg,
db: db,
@@ -255,6 +262,7 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer
annotation.id,
annotation.epoch as time,
annotation.epoch_end as time_end,
annotation.dashboard_uid,
annotation.dashboard_id,
annotation.panel_id,
annotation.new_state,
@@ -292,11 +300,18 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer
params = append(params, query.AlertUID, query.OrgID)
}
// nolint: staticcheck
if query.DashboardID != 0 {
sql.WriteString(` AND a.dashboard_id = ?`)
params = append(params, query.DashboardID)
}
// note: orgID is already required above
if query.DashboardUID != "" {
sql.WriteString(` AND a.dashboard_uid = ?`)
params = append(params, query.DashboardUID)
}
if query.PanelID != 0 {
sql.WriteString(` AND a.panel_id = ?`)
params = append(params, query.PanelID)
@@ -351,13 +366,11 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer
}
}
acFilter, err := r.getAccessControlFilter(query.SignedInUser, accessResources)
if err != nil {
return err
}
acFilter, acParams := r.getAccessControlFilter(query.SignedInUser, accessResources)
if acFilter != "" {
sql.WriteString(fmt.Sprintf(" AND (%s)", acFilter))
}
params = append(params, acParams...)
// order of ORDER BY arguments match the order of a sql index for performance
orderBy := " ORDER BY a.org_id, a.epoch_end DESC, a.epoch DESC"
@@ -377,41 +390,30 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuer
return items, err
}
func (r *xormRepositoryImpl) getAccessControlFilter(user identity.Requester, accessResources *accesscontrol.AccessResources) (string, error) {
func (r *xormRepositoryImpl) getAccessControlFilter(user identity.Requester, accessResources *accesscontrol.AccessResources) (string, []any) {
if accessResources.SkipAccessControlFilter {
return "", nil
}
var filters []string
var params []any
if accessResources.CanAccessOrgAnnotations {
filters = append(filters, "a.dashboard_id = 0")
}
if accessResources.CanAccessDashAnnotations {
var dashboardIDs []int64
for _, id := range accessResources.Dashboards {
dashboardIDs = append(dashboardIDs, id)
}
var inClause string
if len(dashboardIDs) == 0 {
inClause = "SELECT * FROM (SELECT 0 LIMIT 0) tt" // empty set
if len(accessResources.Dashboards) == 0 {
filters = append(filters, "1=0") // empty set
} else {
b := make([]byte, 0, 3*len(dashboardIDs))
b = strconv.AppendInt(b, dashboardIDs[0], 10)
for _, num := range dashboardIDs[1:] {
b = append(b, ',')
b = strconv.AppendInt(b, num, 10)
filters = append(filters, fmt.Sprintf("a.dashboard_uid IN (%s)", strings.Repeat("?,", len(accessResources.Dashboards)-1)+"?"))
for uid := range accessResources.Dashboards {
params = append(params, uid)
}
inClause = string(b)
}
filters = append(filters, fmt.Sprintf("a.dashboard_id IN (%s)", inClause))
}
return strings.Join(filters, " OR "), nil
return strings.Join(filters, " OR "), params
}
func (r *xormRepositoryImpl) Delete(ctx context.Context, params *annotations.DeleteParams) error {
@@ -433,14 +435,27 @@ func (r *xormRepositoryImpl) Delete(ctx context.Context, params *annotations.Del
if _, err := sess.Exec(sql, params.ID, params.OrgID); err != nil {
return err
}
} else if params.DashboardUID != "" {
annoTagSQL = "DELETE FROM annotation_tag WHERE annotation_id IN (SELECT id FROM annotation WHERE dashboard_uid = ? AND panel_id = ? AND org_id = ?)"
sql = "DELETE FROM annotation WHERE dashboard_uid = ? AND panel_id = ? AND org_id = ?"
if _, err := sess.Exec(annoTagSQL, params.DashboardUID, params.PanelID, params.OrgID); err != nil {
return err
}
if _, err := sess.Exec(sql, params.DashboardUID, params.PanelID, params.OrgID); err != nil {
return err
}
} else {
annoTagSQL = "DELETE FROM annotation_tag WHERE annotation_id IN (SELECT id FROM annotation WHERE dashboard_id = ? AND panel_id = ? AND org_id = ?)"
sql = "DELETE FROM annotation WHERE dashboard_id = ? AND panel_id = ? AND org_id = ?"
// nolint: staticcheck
if _, err := sess.Exec(annoTagSQL, params.DashboardID, params.PanelID, params.OrgID); err != nil {
return err
}
// nolint: staticcheck
if _, err := sess.Exec(sql, params.DashboardID, params.PanelID, params.OrgID); err != nil {
return err
}
@@ -78,14 +78,15 @@ func TestIntegrationAnnotations(t *testing.T) {
var err error
annotation := &annotations.Item{
OrgID: 1,
UserID: 1,
DashboardID: dashboard.ID,
Text: "hello",
Type: "alert",
Epoch: 10,
Tags: []string{"outage", "error", "type:outage", "server:server-1"},
Data: simplejson.NewFromAny(map[string]any{"data1": "I am a cool data", "data2": "I am another cool data"}),
OrgID: 1,
UserID: 1,
DashboardID: dashboard.ID, // nolint: staticcheck
DashboardUID: dashboard.UID,
Text: "hello",
Type: "alert",
Epoch: 10,
Tags: []string{"outage", "error", "type:outage", "server:server-1"},
Data: simplejson.NewFromAny(map[string]any{"data1": "I am a cool data", "data2": "I am another cool data"}),
}
err = store.Add(context.Background(), annotation)
require.NoError(t, err)
@@ -93,14 +94,15 @@ func TestIntegrationAnnotations(t *testing.T) {
assert.Equal(t, annotation.Epoch, annotation.EpochEnd)
annotation2 := &annotations.Item{
OrgID: 1,
UserID: 1,
DashboardID: dashboard2.ID,
Text: "hello",
Type: "alert",
Epoch: 21, // Should swap epoch & epochEnd
EpochEnd: 20,
Tags: []string{"outage", "type:outage", "server:server-1", "error"},
OrgID: 1,
UserID: 1,
DashboardID: dashboard2.ID, // nolint: staticcheck
DashboardUID: dashboard2.UID,
Text: "hello",
Type: "alert",
Epoch: 21, // Should swap epoch & epochEnd
EpochEnd: 20,
Tags: []string{"outage", "type:outage", "server:server-1", "error"},
}
err = store.Add(context.Background(), annotation2)
require.NoError(t, err)
@@ -135,7 +137,31 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can query for annotation by dashboard id", func(t *testing.T) {
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardID: dashboard.ID,
DashboardID: dashboard.ID, // nolint: staticcheck
From: 0,
To: 15,
SignedInUser: testUser,
}, &annotation_ac.AccessResources{
Dashboards: map[string]int64{
dashboard.UID: dashboard.ID,
},
CanAccessDashAnnotations: true,
})
require.NoError(t, err)
assert.Len(t, items, 1)
assert.Equal(t, []string{"outage", "error", "type:outage", "server:server-1"}, items[0].Tags)
assert.GreaterOrEqual(t, items[0].Created, int64(0))
assert.GreaterOrEqual(t, items[0].Updated, int64(0))
assert.Equal(t, items[0].Updated, items[0].Created)
})
t.Run("Can query for annotation by dashboard uid", func(t *testing.T) {
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardUID: dashboard.UID,
From: 0,
To: 15,
SignedInUser: testUser,
@@ -234,12 +260,13 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should not find any when item is outside time range", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 12,
To: 15,
SignedInUser: testUser,
@@ -250,12 +277,13 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should not find one when tag filter does not match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 1,
To: 15,
Tags: []string{"asd"},
@@ -267,12 +295,13 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should not find one when type filter does not match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 1,
To: 15,
Type: "alert",
@@ -284,12 +313,13 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should find one when all tag filters does match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 1,
To: 15, // this will exclude the second test annotation
Tags: []string{"outage", "error"},
@@ -315,12 +345,13 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Should find one when all key value tag filters does match", func(t *testing.T) {
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 1,
To: 15,
Tags: []string{"type:outage", "server:server-1"},
@@ -333,13 +364,14 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can update annotation and remove all tags", func(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 0,
To: 15,
SignedInUser: testUser,
}
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), query, accRes)
@@ -368,13 +400,14 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can update annotation with new tags", func(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 0,
To: 15,
SignedInUser: testUser,
}
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), query, accRes)
@@ -401,13 +434,14 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can update annotation with additional tags", func(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 0,
To: 15,
SignedInUser: testUser,
}
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), query, accRes)
@@ -434,13 +468,14 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can update annotations with data", func(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 0,
To: 15,
SignedInUser: testUser,
}
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), query, accRes)
@@ -470,13 +505,14 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can delete annotation", func(t *testing.T) {
query := annotations.ItemQuery{
OrgID: 1,
DashboardID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: dashboard.UID,
From: 0,
To: 15,
SignedInUser: testUser,
}
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{"foo": 1},
Dashboards: map[string]int64{dashboard.UID: 1},
CanAccessDashAnnotations: true,
}
items, err := store.Get(context.Background(), query, accRes)
@@ -493,14 +529,15 @@ func TestIntegrationAnnotations(t *testing.T) {
t.Run("Can delete annotation using dashboard id and panel id", func(t *testing.T) {
annotation3 := &annotations.Item{
OrgID: 1,
UserID: 1,
DashboardID: dashboard2.ID,
Text: "toBeDeletedWithPanelId",
Type: "alert",
Epoch: 11,
Tags: []string{"test"},
PanelID: 20,
OrgID: 1,
UserID: 1,
DashboardID: dashboard2.ID, // nolint: staticcheck
DashboardUID: dashboard2.UID,
Text: "toBeDeletedWithPanelId",
Type: "alert",
Epoch: 11,
Tags: []string{"test"},
PanelID: 20,
}
err = store.Add(context.Background(), annotation3)
require.NoError(t, err)
@@ -520,9 +557,46 @@ func TestIntegrationAnnotations(t *testing.T) {
items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err)
dashboardId := items[0].DashboardID
panelId := items[0].PanelID
err = store.Delete(context.Background(), &annotations.DeleteParams{DashboardID: dashboardId, PanelID: panelId, OrgID: 1})
// nolint:staticcheck
err = store.Delete(context.Background(), &annotations.DeleteParams{DashboardID: items[0].DashboardID, PanelID: items[0].PanelID, OrgID: 1})
require.NoError(t, err)
items, err = store.Get(context.Background(), query, accRes)
require.NoError(t, err)
assert.Empty(t, items)
})
t.Run("Can delete annotation using dashboard uid and panel id", func(t *testing.T) {
annotation3 := &annotations.Item{
OrgID: 1,
UserID: 1,
DashboardUID: dashboard2.UID,
Text: "toBeDeletedWithPanelId",
Type: "alert",
Epoch: 11,
Tags: []string{"test"},
PanelID: 20,
}
err = store.Add(context.Background(), annotation3)
require.NoError(t, err)
accRes := &annotation_ac.AccessResources{
Dashboards: map[string]int64{
dashboard2.UID: dashboard2.ID,
},
CanAccessDashAnnotations: true,
}
query := annotations.ItemQuery{
OrgID: 1,
AnnotationID: annotation3.ID,
SignedInUser: testUser,
}
items, err := store.Get(context.Background(), query, accRes)
require.NoError(t, err)
// nolint:staticcheck
err = store.Delete(context.Background(), &annotations.DeleteParams{DashboardUID: *items[0].DashboardUID, PanelID: items[0].PanelID, OrgID: 1})
require.NoError(t, err)
items, err = store.Get(context.Background(), query, accRes)
@@ -635,15 +709,16 @@ func benchmarkFindTags(b *testing.B, numAnnotations int) {
require.NoError(b, err)
annotationWithTheTag := annotations.Item{
ID: int64(numAnnotations) + 1,
OrgID: 1,
UserID: 1,
DashboardID: int64(1),
Text: "hello",
Type: "alert",
Epoch: 10,
Tags: []string{"outage", "error", "type:outage", "server:server-1"},
Data: simplejson.NewFromAny(map[string]any{"data1": "I am a cool data", "data2": "I am another cool data"}),
ID: int64(numAnnotations) + 1,
OrgID: 1,
UserID: 1,
DashboardID: 1, // nolint: staticcheck
DashboardUID: "uid",
Text: "hello",
Type: "alert",
Epoch: 10,
Tags: []string{"outage", "error", "type:outage", "server:server-1"},
Data: simplejson.NewFromAny(map[string]any{"data1": "I am a cool data", "data2": "I am another cool data"}),
}
err = store.Add(context.Background(), &annotationWithTheTag)
require.NoError(b, err)