Chore: Add context to playlist (#41337)

* Add context to playlist

* Add AddEventListenerCtx and more context

* Update pkg/services/sqlstore/playlist.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Update pkg/services/sqlstore/playlist.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Update pkg/services/sqlstore/playlist.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Fix lint

* Rename listener help function

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
idafurjes
2021-11-19 14:32:14 +01:00
committed by GitHub
co-authored by Marcus Efraimsson
parent 67f43cd7ab
commit 87f148aa27
12 changed files with 171 additions and 155 deletions
+9 -9
View File
@@ -23,7 +23,7 @@ import (
type DashboardService interface {
SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error)
ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*models.Dashboard, error)
DeleteDashboard(dashboardId int64, orgId int64) error
DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error
MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error
}
@@ -34,7 +34,7 @@ type DashboardProvisioningService interface {
GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error)
GetProvisionedDashboardDataByDashboardID(dashboardID int64) (*models.DashboardProvisioning, error)
UnprovisionDashboard(dashboardID int64) error
DeleteProvisionedDashboard(dashboardID int64, orgID int64) error
DeleteProvisionedDashboard(ctx context.Context, dashboardID int64, orgID int64) error
}
// NewService is a factory for creating a new dashboard service.
@@ -298,16 +298,16 @@ func (dr *dashboardServiceImpl) SaveDashboard(ctx context.Context, dto *SaveDash
// DeleteDashboard removes dashboard from the DB. Errors out if the dashboard was provisioned. Should be used for
// operations by the user where we want to make sure user does not delete provisioned dashboard.
func (dr *dashboardServiceImpl) DeleteDashboard(dashboardId int64, orgId int64) error {
return dr.deleteDashboard(dashboardId, orgId, true)
func (dr *dashboardServiceImpl) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
return dr.deleteDashboard(ctx, dashboardId, orgId, true)
}
// DeleteProvisionedDashboard removes dashboard from the DB even if it is provisioned.
func (dr *dashboardServiceImpl) DeleteProvisionedDashboard(dashboardId int64, orgId int64) error {
return dr.deleteDashboard(dashboardId, orgId, false)
func (dr *dashboardServiceImpl) DeleteProvisionedDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
return dr.deleteDashboard(ctx, dashboardId, orgId, false)
}
func (dr *dashboardServiceImpl) deleteDashboard(dashboardId int64, orgId int64, validateProvisionedDashboard bool) error {
func (dr *dashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId int64, orgId int64, validateProvisionedDashboard bool) error {
if validateProvisionedDashboard {
provisionedData, err := dr.GetProvisionedDashboardDataByDashboardID(dashboardId)
if err != nil {
@@ -319,7 +319,7 @@ func (dr *dashboardServiceImpl) deleteDashboard(dashboardId int64, orgId int64,
}
}
cmd := &models.DeleteDashboardCommand{OrgId: orgId, Id: dashboardId}
return bus.Dispatch(cmd)
return bus.DispatchCtx(ctx, cmd)
}
func (dr *dashboardServiceImpl) ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (
@@ -374,7 +374,7 @@ func (s *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDas
return s.SaveDashboard(context.Background(), dto, true)
}
func (s *FakeDashboardService) DeleteDashboard(dashboardId int64, orgId int64) error {
func (s *FakeDashboardService) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
for index, dash := range s.SavedDashboards {
if dash.Dashboard.Id == dashboardId && dash.OrgId == orgId {
s.SavedDashboards = append(s.SavedDashboards[:index], s.SavedDashboards[index+1:]...)
@@ -237,14 +237,14 @@ func TestDashboardService(t *testing.T) {
t.Run("Given provisioned dashboard", func(t *testing.T) {
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) {
result := setupDeleteHandlers(t, &fakeStore, true)
err := service.DeleteProvisionedDashboard(1, 1)
err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err)
require.True(t, result.deleteWasCalled)
})
t.Run("DeleteDashboard should fail to delete it", func(t *testing.T) {
result := setupDeleteHandlers(t, &fakeStore, true)
err := service.DeleteDashboard(1, 1)
err := service.DeleteDashboard(context.Background(), 1, 1)
require.Equal(t, err, models.ErrDashboardCannotDeleteProvisionedDashboard)
require.False(t, result.deleteWasCalled)
})
@@ -254,13 +254,13 @@ func TestDashboardService(t *testing.T) {
result := setupDeleteHandlers(t, &fakeStore, false)
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) {
err := service.DeleteProvisionedDashboard(1, 1)
err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err)
require.True(t, result.deleteWasCalled)
})
t.Run("DeleteDashboard should delete it", func(t *testing.T) {
err := service.DeleteDashboard(1, 1)
err := service.DeleteDashboard(context.Background(), 1, 1)
require.NoError(t, err)
require.True(t, result.deleteWasCalled)
})
@@ -103,7 +103,7 @@ func (fr *FileReader) walkDisk(ctx context.Context) error {
return err
}
fr.handleMissingDashboardFiles(provisionedDashboardRefs, filesFoundOnDisk)
fr.handleMissingDashboardFiles(ctx, provisionedDashboardRefs, filesFoundOnDisk)
usageTracker := newUsageTracker()
if fr.FoldersFromFilesStructure {
@@ -184,7 +184,7 @@ func (fr *FileReader) storeDashboardsInFoldersFromFileStructure(ctx context.Cont
}
// handleMissingDashboardFiles will unprovision or delete dashboards which are missing on disk.
func (fr *FileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[string]*models.DashboardProvisioning,
func (fr *FileReader) handleMissingDashboardFiles(ctx context.Context, provisionedDashboardRefs map[string]*models.DashboardProvisioning,
filesFoundOnDisk map[string]os.FileInfo) {
// find dashboards to delete since json file is missing
var dashboardsToDelete []int64
@@ -209,7 +209,7 @@ func (fr *FileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[s
// delete dashboards missing JSON file
for _, dashboardID := range dashboardsToDelete {
fr.log.Debug("deleting provisioned dashboard, missing on disk", "id", dashboardID)
err := fr.dashboardProvisioningService.DeleteProvisionedDashboard(dashboardID, fr.Cfg.OrgID)
err := fr.dashboardProvisioningService.DeleteProvisionedDashboard(ctx, dashboardID, fr.Cfg.OrgID)
if err != nil {
fr.log.Error("failed to delete dashboard", "id", dashboardID, "error", err)
}
@@ -577,7 +577,7 @@ func (s *fakeDashboardProvisioningService) SaveProvisionedDashboard(ctx context.
if copyDto.Dashboard.Id == 0 {
copyDto.Dashboard.Id = rand.Int63n(1000000)
} else {
err := s.DeleteProvisionedDashboard(dto.Dashboard.Id, dto.Dashboard.OrgId)
err := s.DeleteProvisionedDashboard(context.Background(), dto.Dashboard.Id, dto.Dashboard.OrgId)
// Lets delete existing so we do not have duplicates
if err != nil {
return nil, err
@@ -619,7 +619,7 @@ func (s *fakeDashboardProvisioningService) UnprovisionDashboard(dashboardID int6
return nil
}
func (s *fakeDashboardProvisioningService) DeleteProvisionedDashboard(dashboardID int64, orgID int64) error {
func (s *fakeDashboardProvisioningService) DeleteProvisionedDashboard(ctx context.Context, dashboardID int64, orgID int64) error {
err := s.UnprovisionDashboard(dashboardID)
if err != nil {
return err
+112 -100
View File
@@ -1,118 +1,126 @@
package sqlstore
import (
"context"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
)
func init() {
bus.AddHandler("sql", CreatePlaylist)
bus.AddHandler("sql", UpdatePlaylist)
bus.AddHandler("sql", DeletePlaylist)
bus.AddHandler("sql", SearchPlaylists)
bus.AddHandler("sql", GetPlaylist)
bus.AddHandler("sql", GetPlaylistItem)
func (ss *SQLStore) addPlaylistQueryAndCommandHandlers() {
bus.AddHandlerCtx("sql", ss.CreatePlaylist)
bus.AddHandlerCtx("sql", ss.UpdatePlaylist)
bus.AddHandlerCtx("sql", ss.DeletePlaylist)
bus.AddHandlerCtx("sql", ss.SearchPlaylists)
bus.AddHandlerCtx("sql", ss.GetPlaylist)
bus.AddHandlerCtx("sql", ss.GetPlaylistItem)
}
func CreatePlaylist(cmd *models.CreatePlaylistCommand) error {
playlist := models.Playlist{
Name: cmd.Name,
Interval: cmd.Interval,
OrgId: cmd.OrgId,
}
func (ss *SQLStore) CreatePlaylist(ctx context.Context, cmd *models.CreatePlaylistCommand) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
playlist := models.Playlist{
Name: cmd.Name,
Interval: cmd.Interval,
OrgId: cmd.OrgId,
}
_, err := x.Insert(&playlist)
if err != nil {
_, err := sess.Insert(&playlist)
if err != nil {
return err
}
playlistItems := make([]models.PlaylistItem, 0)
for _, item := range cmd.Items {
playlistItems = append(playlistItems, models.PlaylistItem{
PlaylistId: playlist.Id,
Type: item.Type,
Value: item.Value,
Order: item.Order,
Title: item.Title,
})
}
_, err = sess.Insert(&playlistItems)
cmd.Result = &playlist
return err
}
playlistItems := make([]models.PlaylistItem, 0)
for _, item := range cmd.Items {
playlistItems = append(playlistItems, models.PlaylistItem{
PlaylistId: playlist.Id,
Type: item.Type,
Value: item.Value,
Order: item.Order,
Title: item.Title,
})
}
_, err = x.Insert(&playlistItems)
cmd.Result = &playlist
return err
})
}
func UpdatePlaylist(cmd *models.UpdatePlaylistCommand) error {
playlist := models.Playlist{
Id: cmd.Id,
OrgId: cmd.OrgId,
Name: cmd.Name,
Interval: cmd.Interval,
}
func (ss *SQLStore) UpdatePlaylist(ctx context.Context, cmd *models.UpdatePlaylistCommand) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
playlist := models.Playlist{
Id: cmd.Id,
OrgId: cmd.OrgId,
Name: cmd.Name,
Interval: cmd.Interval,
}
existingPlaylist := x.Where("id = ? AND org_id = ?", cmd.Id, cmd.OrgId).Find(models.Playlist{})
existingPlaylist := sess.Where("id = ? AND org_id = ?", cmd.Id, cmd.OrgId).Find(models.Playlist{})
if existingPlaylist == nil {
return models.ErrPlaylistNotFound
}
if existingPlaylist == nil {
return models.ErrPlaylistNotFound
}
cmd.Result = &models.PlaylistDTO{
Id: playlist.Id,
OrgId: playlist.OrgId,
Name: playlist.Name,
Interval: playlist.Interval,
}
cmd.Result = &models.PlaylistDTO{
Id: playlist.Id,
OrgId: playlist.OrgId,
Name: playlist.Name,
Interval: playlist.Interval,
}
_, err := x.ID(cmd.Id).Cols("name", "interval").Update(&playlist)
_, err := sess.ID(cmd.Id).Cols("name", "interval").Update(&playlist)
if err != nil {
return err
}
rawSQL := "DELETE FROM playlist_item WHERE playlist_id = ?"
_, err = sess.Exec(rawSQL, cmd.Id)
if err != nil {
return err
}
playlistItems := make([]models.PlaylistItem, 0)
for index, item := range cmd.Items {
playlistItems = append(playlistItems, models.PlaylistItem{
PlaylistId: playlist.Id,
Type: item.Type,
Value: item.Value,
Order: index + 1,
Title: item.Title,
})
}
_, err = sess.Insert(&playlistItems)
if err != nil {
return err
}
rawSQL := "DELETE FROM playlist_item WHERE playlist_id = ?"
_, err = x.Exec(rawSQL, cmd.Id)
if err != nil {
return err
}
playlistItems := make([]models.PlaylistItem, 0)
for index, item := range cmd.Items {
playlistItems = append(playlistItems, models.PlaylistItem{
PlaylistId: playlist.Id,
Type: item.Type,
Value: item.Value,
Order: index + 1,
Title: item.Title,
})
}
_, err = x.Insert(&playlistItems)
return err
})
}
func GetPlaylist(query *models.GetPlaylistByIdQuery) error {
func (ss *SQLStore) GetPlaylist(ctx context.Context, query *models.GetPlaylistByIdQuery) error {
if query.Id == 0 {
return models.ErrCommandValidationFailed
}
playlist := models.Playlist{}
_, err := x.ID(query.Id).Get(&playlist)
return ss.WithDbSession(ctx, func(sess *DBSession) error {
playlist := models.Playlist{}
_, err := sess.ID(query.Id).Get(&playlist)
query.Result = &playlist
query.Result = &playlist
return err
return err
})
}
func DeletePlaylist(cmd *models.DeletePlaylistCommand) error {
func (ss *SQLStore) DeletePlaylist(ctx context.Context, cmd *models.DeletePlaylistCommand) error {
if cmd.Id == 0 || cmd.OrgId == 0 {
return models.ErrCommandValidationFailed
}
return inTransaction(func(sess *DBSession) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
var rawPlaylistSQL = "DELETE FROM playlist WHERE id = ? and org_id = ?"
_, err := sess.Exec(rawPlaylistSQL, cmd.Id, cmd.OrgId)
@@ -127,31 +135,35 @@ func DeletePlaylist(cmd *models.DeletePlaylistCommand) error {
})
}
func SearchPlaylists(query *models.GetPlaylistsQuery) error {
var playlists = make(models.Playlists, 0)
func (ss *SQLStore) SearchPlaylists(ctx context.Context, query *models.GetPlaylistsQuery) error {
return ss.WithDbSession(ctx, func(dbSess *DBSession) error {
var playlists = make(models.Playlists, 0)
sess := x.Limit(query.Limit)
sess := dbSess.Limit(query.Limit)
if query.Name != "" {
sess.Where("name LIKE ?", "%"+query.Name+"%")
}
if query.Name != "" {
sess.Where("name LIKE ?", "%"+query.Name+"%")
}
sess.Where("org_id = ?", query.OrgId)
err := sess.Find(&playlists)
query.Result = playlists
sess.Where("org_id = ?", query.OrgId)
err := sess.Find(&playlists)
query.Result = playlists
return err
return err
})
}
func GetPlaylistItem(query *models.GetPlaylistItemsByIdQuery) error {
if query.PlaylistId == 0 {
return models.ErrCommandValidationFailed
}
func (ss *SQLStore) GetPlaylistItem(ctx context.Context, query *models.GetPlaylistItemsByIdQuery) error {
return ss.WithDbSession(ctx, func(sess *DBSession) error {
if query.PlaylistId == 0 {
return models.ErrCommandValidationFailed
}
var playlistItems = make([]models.PlaylistItem, 0)
err := x.Where("playlist_id=?", query.PlaylistId).Find(&playlistItems)
var playlistItems = make([]models.PlaylistItem, 0)
err := sess.Where("playlist_id=?", query.PlaylistId).Find(&playlistItems)
query.Result = &playlistItems
query.Result = &playlistItems
return err
return err
})
}
+8 -7
View File
@@ -4,6 +4,7 @@
package sqlstore
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/models"
@@ -11,7 +12,7 @@ import (
)
func TestPlaylistDataAccess(t *testing.T) {
InitTestDB(t)
ss := InitTestDB(t)
t.Run("Can create playlist", func(t *testing.T) {
items := []models.PlaylistItemDTO{
@@ -19,7 +20,7 @@ func TestPlaylistDataAccess(t *testing.T) {
{Title: "Backend response times", Value: "3", Type: "dashboard_by_id"},
}
cmd := models.CreatePlaylistCommand{Name: "NYC office", Interval: "10m", OrgId: 1, Items: items}
err := CreatePlaylist(&cmd)
err := ss.CreatePlaylist(context.Background(), &cmd)
require.NoError(t, err)
t.Run("Can update playlist", func(t *testing.T) {
@@ -28,17 +29,17 @@ func TestPlaylistDataAccess(t *testing.T) {
{Title: "Backend response times", Value: "2", Type: "dashboard_by_id"},
}
query := models.UpdatePlaylistCommand{Name: "NYC office ", OrgId: 1, Id: 1, Interval: "10s", Items: items}
err = UpdatePlaylist(&query)
err = ss.UpdatePlaylist(context.Background(), &query)
require.NoError(t, err)
})
t.Run("Can remove playlist", func(t *testing.T) {
deleteQuery := models.DeletePlaylistCommand{Id: 1, OrgId: 1}
err = DeletePlaylist(&deleteQuery)
err = ss.DeletePlaylist(context.Background(), &deleteQuery)
require.NoError(t, err)
getQuery := models.GetPlaylistByIdQuery{Id: 1}
err = GetPlaylist(&getQuery)
err = ss.GetPlaylist(context.Background(), &getQuery)
require.NoError(t, err)
require.Equal(t, int64(0), getQuery.Result.Id, "playlist should've been removed")
})
@@ -46,7 +47,7 @@ func TestPlaylistDataAccess(t *testing.T) {
t.Run("Delete playlist that doesn't exist", func(t *testing.T) {
deleteQuery := models.DeletePlaylistCommand{Id: 1, OrgId: 1}
err := DeletePlaylist(&deleteQuery)
err := ss.DeletePlaylist(context.Background(), &deleteQuery)
require.NoError(t, err)
})
@@ -62,7 +63,7 @@ func TestPlaylistDataAccess(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
err := DeletePlaylist(&tc.cmd)
err := ss.DeletePlaylist(context.Background(), &tc.cmd)
require.EqualError(t, err, models.ErrCommandValidationFailed.Error())
})
}
+1
View File
@@ -121,6 +121,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
ss.addTempUserQueryAndCommandHandlers()
ss.addDashboardVersionQueryAndCommandHandlers()
ss.addAPIKeysQueryAndCommandHandlers()
ss.addPlaylistQueryAndCommandHandlers()
// if err := ss.Reset(); err != nil {
// return nil, err