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
parent 67f43cd7ab
commit 87f148aa27
12 changed files with 171 additions and 155 deletions

View File

@@ -251,7 +251,7 @@ func (hs *HTTPServer) deleteDashboard(c *models.ReqContext) response.Response {
} }
svc := dashboards.NewService(hs.SQLStore) svc := dashboards.NewService(hs.SQLStore)
err = svc.DeleteDashboard(dash.Id, c.OrgId) err = svc.DeleteDashboard(c.Req.Context(), dash.Id, c.OrgId)
if err != nil { if err != nil {
var dashboardErr models.DashboardErr var dashboardErr models.DashboardErr
if ok := errors.As(err, &dashboardErr); ok { if ok := errors.As(err, &dashboardErr); ok {

View File

@@ -1,6 +1,8 @@
package api package api
import ( import (
"context"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
@@ -9,7 +11,7 @@ import (
func ValidateOrgPlaylist(c *models.ReqContext) { func ValidateOrgPlaylist(c *models.ReqContext) {
id := c.ParamsInt64(":id") id := c.ParamsInt64(":id")
query := models.GetPlaylistByIdQuery{Id: id} query := models.GetPlaylistByIdQuery{Id: id}
err := bus.Dispatch(&query) err := bus.DispatchCtx(c.Req.Context(), &query)
if err != nil { if err != nil {
c.JsonApiErr(404, "Playlist not found", err) c.JsonApiErr(404, "Playlist not found", err)
@@ -41,7 +43,7 @@ func SearchPlaylists(c *models.ReqContext) response.Response {
OrgId: c.OrgId, OrgId: c.OrgId,
} }
err := bus.Dispatch(&searchQuery) err := bus.DispatchCtx(c.Req.Context(), &searchQuery)
if err != nil { if err != nil {
return response.Error(500, "Search failed", err) return response.Error(500, "Search failed", err)
} }
@@ -53,11 +55,11 @@ func GetPlaylist(c *models.ReqContext) response.Response {
id := c.ParamsInt64(":id") id := c.ParamsInt64(":id")
cmd := models.GetPlaylistByIdQuery{Id: id} cmd := models.GetPlaylistByIdQuery{Id: id}
if err := bus.Dispatch(&cmd); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Playlist not found", err) return response.Error(500, "Playlist not found", err)
} }
playlistDTOs, _ := LoadPlaylistItemDTOs(id) playlistDTOs, _ := LoadPlaylistItemDTOs(c.Req.Context(), id)
dto := &models.PlaylistDTO{ dto := &models.PlaylistDTO{
Id: cmd.Result.Id, Id: cmd.Result.Id,
@@ -70,8 +72,8 @@ func GetPlaylist(c *models.ReqContext) response.Response {
return response.JSON(200, dto) return response.JSON(200, dto)
} }
func LoadPlaylistItemDTOs(id int64) ([]models.PlaylistItemDTO, error) { func LoadPlaylistItemDTOs(ctx context.Context, id int64) ([]models.PlaylistItemDTO, error) {
playlistitems, err := LoadPlaylistItems(id) playlistitems, err := LoadPlaylistItems(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -93,9 +95,9 @@ func LoadPlaylistItemDTOs(id int64) ([]models.PlaylistItemDTO, error) {
return playlistDTOs, nil return playlistDTOs, nil
} }
func LoadPlaylistItems(id int64) ([]models.PlaylistItem, error) { func LoadPlaylistItems(ctx context.Context, id int64) ([]models.PlaylistItem, error) {
itemQuery := models.GetPlaylistItemsByIdQuery{PlaylistId: id} itemQuery := models.GetPlaylistItemsByIdQuery{PlaylistId: id}
if err := bus.Dispatch(&itemQuery); err != nil { if err := bus.DispatchCtx(ctx, &itemQuery); err != nil {
return nil, err return nil, err
} }
@@ -105,7 +107,7 @@ func LoadPlaylistItems(id int64) ([]models.PlaylistItem, error) {
func GetPlaylistItems(c *models.ReqContext) response.Response { func GetPlaylistItems(c *models.ReqContext) response.Response {
id := c.ParamsInt64(":id") id := c.ParamsInt64(":id")
playlistDTOs, err := LoadPlaylistItemDTOs(id) playlistDTOs, err := LoadPlaylistItemDTOs(c.Req.Context(), id)
if err != nil { if err != nil {
return response.Error(500, "Could not load playlist items", err) return response.Error(500, "Could not load playlist items", err)
@@ -129,7 +131,7 @@ func DeletePlaylist(c *models.ReqContext) response.Response {
id := c.ParamsInt64(":id") id := c.ParamsInt64(":id")
cmd := models.DeletePlaylistCommand{Id: id, OrgId: c.OrgId} cmd := models.DeletePlaylistCommand{Id: id, OrgId: c.OrgId}
if err := bus.Dispatch(&cmd); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Failed to delete playlist", err) return response.Error(500, "Failed to delete playlist", err)
} }
@@ -139,7 +141,7 @@ func DeletePlaylist(c *models.ReqContext) response.Response {
func CreatePlaylist(c *models.ReqContext, cmd models.CreatePlaylistCommand) response.Response { func CreatePlaylist(c *models.ReqContext, cmd models.CreatePlaylistCommand) response.Response {
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
if err := bus.Dispatch(&cmd); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Failed to create playlist", err) return response.Error(500, "Failed to create playlist", err)
} }
@@ -150,11 +152,11 @@ func UpdatePlaylist(c *models.ReqContext, cmd models.UpdatePlaylistCommand) resp
cmd.OrgId = c.OrgId cmd.OrgId = c.OrgId
cmd.Id = c.ParamsInt64(":id") cmd.Id = c.ParamsInt64(":id")
if err := bus.Dispatch(&cmd); err != nil { if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Failed to save playlist", err) return response.Error(500, "Failed to save playlist", err)
} }
playlistDTOs, err := LoadPlaylistItemDTOs(cmd.Id) playlistDTOs, err := LoadPlaylistItemDTOs(c.Req.Context(), cmd.Id)
if err != nil { if err != nil {
return response.Error(500, "Failed to save playlist", err) return response.Error(500, "Failed to save playlist", err)
} }

View File

@@ -12,12 +12,12 @@ import (
"github.com/grafana/grafana/pkg/services/search" "github.com/grafana/grafana/pkg/services/search"
) )
func populateDashboardsByID(dashboardByIDs []int64, dashboardIDOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) { func populateDashboardsByID(ctx context.Context, dashboardByIDs []int64, dashboardIDOrder map[int64]int) (dtos.PlaylistDashboardsSlice, error) {
result := make(dtos.PlaylistDashboardsSlice, 0) result := make(dtos.PlaylistDashboardsSlice, 0)
if len(dashboardByIDs) > 0 { if len(dashboardByIDs) > 0 {
dashboardQuery := models.GetDashboardsQuery{DashboardIds: dashboardByIDs} dashboardQuery := models.GetDashboardsQuery{DashboardIds: dashboardByIDs}
if err := bus.Dispatch(&dashboardQuery); err != nil { if err := bus.DispatchCtx(ctx, &dashboardQuery); err != nil {
return result, err return result, err
} }
@@ -67,7 +67,7 @@ func populateDashboardsByTag(ctx context.Context, orgID int64, signedInUser *mod
} }
func LoadPlaylistDashboards(ctx context.Context, orgID int64, signedInUser *models.SignedInUser, playlistID int64) (dtos.PlaylistDashboardsSlice, error) { func LoadPlaylistDashboards(ctx context.Context, orgID int64, signedInUser *models.SignedInUser, playlistID int64) (dtos.PlaylistDashboardsSlice, error) {
playlistItems, _ := LoadPlaylistItems(playlistID) playlistItems, _ := LoadPlaylistItems(ctx, playlistID)
dashboardByIDs := make([]int64, 0) dashboardByIDs := make([]int64, 0)
dashboardByTag := make([]string, 0) dashboardByTag := make([]string, 0)
@@ -89,7 +89,7 @@ func LoadPlaylistDashboards(ctx context.Context, orgID int64, signedInUser *mode
result := make(dtos.PlaylistDashboardsSlice, 0) result := make(dtos.PlaylistDashboardsSlice, 0)
var k, _ = populateDashboardsByID(dashboardByIDs, dashboardIDOrder) var k, _ = populateDashboardsByID(ctx, dashboardByIDs, dashboardIDOrder)
result = append(result, k...) result = append(result, k...)
result = append(result, populateDashboardsByTag(ctx, orgID, signedInUser, dashboardByTag, dashboardTagOrder)...) result = append(result, populateDashboardsByTag(ctx, orgID, signedInUser, dashboardByTag, dashboardTagOrder)...)

View File

@@ -167,7 +167,7 @@ func (b *InProcBus) PublishCtx(ctx context.Context, msg Msg) error {
if listeners, exists := b.listenersWithCtx[msgName]; exists { if listeners, exists := b.listenersWithCtx[msgName]; exists {
params = append(params, reflect.ValueOf(ctx)) params = append(params, reflect.ValueOf(ctx))
params = append(params, reflect.ValueOf(msg)) params = append(params, reflect.ValueOf(msg))
if err := checkListeners(listeners, params); err != nil { if err := callListeners(listeners, params); err != nil {
return err return err
} }
} }
@@ -177,7 +177,7 @@ func (b *InProcBus) PublishCtx(ctx context.Context, msg Msg) error {
if setting.Env == setting.Dev { if setting.Env == setting.Dev {
b.logger.Warn("PublishCtx called with message listener registered using AddEventListener and should be changed to use AddEventListenerCtx", "msgName", msgName) b.logger.Warn("PublishCtx called with message listener registered using AddEventListener and should be changed to use AddEventListenerCtx", "msgName", msgName)
} }
if err := checkListeners(listeners, params); err != nil { if err := callListeners(listeners, params); err != nil {
return err return err
} }
} }
@@ -200,14 +200,14 @@ func (b *InProcBus) Publish(msg Msg) error {
if setting.Env == setting.Dev { if setting.Env == setting.Dev {
b.logger.Warn("Publish called with message handler registered using AddEventHandlerCtx and should be changed to use PublishCtx", "msgName", msgName) b.logger.Warn("Publish called with message handler registered using AddEventHandlerCtx and should be changed to use PublishCtx", "msgName", msgName)
} }
if err := checkListeners(listeners, params); err != nil { if err := callListeners(listeners, params); err != nil {
return err return err
} }
} }
if listeners, exists := b.listeners[msgName]; exists { if listeners, exists := b.listeners[msgName]; exists {
params = append(params, reflect.ValueOf(msg)) params = append(params, reflect.ValueOf(msg))
if err := checkListeners(listeners, params); err != nil { if err := callListeners(listeners, params); err != nil {
return err return err
} }
} }
@@ -215,7 +215,7 @@ func (b *InProcBus) Publish(msg Msg) error {
return nil return nil
} }
func checkListeners(listeners []HandlerFunc, params []reflect.Value) error { func callListeners(listeners []HandlerFunc, params []reflect.Value) error {
for _, listenerHandler := range listeners { for _, listenerHandler := range listeners {
ret := reflect.ValueOf(listenerHandler).Call(params) ret := reflect.ValueOf(listenerHandler).Call(params)
e := ret[0].Interface() e := ret[0].Interface()

View File

@@ -19,7 +19,7 @@ func ProvideService(pluginStore plugins.Store, pluginDashboardManager plugins.Pl
pluginDashboardManager: pluginDashboardManager, pluginDashboardManager: pluginDashboardManager,
logger: log.New("plugindashboards"), logger: log.New("plugindashboards"),
} }
bus.AddEventListener(s.handlePluginStateChanged) bus.AddEventListenerCtx(s.handlePluginStateChanged)
s.updateAppDashboards() s.updateAppDashboards()
return s return s
} }
@@ -72,7 +72,7 @@ func (s *Service) syncPluginDashboards(ctx context.Context, plugin plugins.Plugi
s.logger.Info("Deleting plugin dashboard", "pluginId", plugin.ID, "dashboard", dash.Slug) s.logger.Info("Deleting plugin dashboard", "pluginId", plugin.ID, "dashboard", dash.Slug)
deleteCmd := models.DeleteDashboardCommand{OrgId: orgID, Id: dash.DashboardId} deleteCmd := models.DeleteDashboardCommand{OrgId: orgID, Id: dash.DashboardId}
if err := bus.Dispatch(&deleteCmd); err != nil { if err := bus.DispatchCtx(ctx, &deleteCmd); err != nil {
s.logger.Error("Failed to auto update app dashboard", "pluginId", plugin.ID, "error", err) s.logger.Error("Failed to auto update app dashboard", "pluginId", plugin.ID, "error", err)
return return
} }
@@ -108,26 +108,26 @@ func (s *Service) syncPluginDashboards(ctx context.Context, plugin plugins.Plugi
} }
} }
func (s *Service) handlePluginStateChanged(event *models.PluginStateChangedEvent) error { func (s *Service) handlePluginStateChanged(ctx context.Context, event *models.PluginStateChangedEvent) error {
s.logger.Info("Plugin state changed", "pluginId", event.PluginId, "enabled", event.Enabled) s.logger.Info("Plugin state changed", "pluginId", event.PluginId, "enabled", event.Enabled)
if event.Enabled { if event.Enabled {
p, exists := s.pluginStore.Plugin(context.TODO(), event.PluginId) p, exists := s.pluginStore.Plugin(ctx, event.PluginId)
if !exists { if !exists {
return fmt.Errorf("plugin %s not found. Could not sync plugin dashboards", event.PluginId) return fmt.Errorf("plugin %s not found. Could not sync plugin dashboards", event.PluginId)
} }
s.syncPluginDashboards(context.TODO(), p, event.OrgId) s.syncPluginDashboards(ctx, p, event.OrgId)
} else { } else {
query := models.GetDashboardsByPluginIdQuery{PluginId: event.PluginId, OrgId: event.OrgId} query := models.GetDashboardsByPluginIdQuery{PluginId: event.PluginId, OrgId: event.OrgId}
if err := bus.DispatchCtx(context.TODO(), &query); err != nil { if err := bus.DispatchCtx(ctx, &query); err != nil {
return err return err
} }
for _, dash := range query.Result { for _, dash := range query.Result {
s.logger.Info("Deleting plugin dashboard", "pluginId", event.PluginId, "dashboard", dash.Slug) s.logger.Info("Deleting plugin dashboard", "pluginId", event.PluginId, "dashboard", dash.Slug)
deleteCmd := models.DeleteDashboardCommand{OrgId: dash.OrgId, Id: dash.Id} deleteCmd := models.DeleteDashboardCommand{OrgId: dash.OrgId, Id: dash.Id}
if err := bus.Dispatch(&deleteCmd); err != nil { if err := bus.DispatchCtx(ctx, &deleteCmd); err != nil {
return err return err
} }
} }

View File

@@ -23,7 +23,7 @@ import (
type DashboardService interface { type DashboardService interface {
SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error)
ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*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 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) GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error)
GetProvisionedDashboardDataByDashboardID(dashboardID int64) (*models.DashboardProvisioning, error) GetProvisionedDashboardDataByDashboardID(dashboardID int64) (*models.DashboardProvisioning, error)
UnprovisionDashboard(dashboardID int64) 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. // 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 // 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. // 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 { func (dr *dashboardServiceImpl) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
return dr.deleteDashboard(dashboardId, orgId, true) return dr.deleteDashboard(ctx, dashboardId, orgId, true)
} }
// DeleteProvisionedDashboard removes dashboard from the DB even if it is provisioned. // DeleteProvisionedDashboard removes dashboard from the DB even if it is provisioned.
func (dr *dashboardServiceImpl) DeleteProvisionedDashboard(dashboardId int64, orgId int64) error { func (dr *dashboardServiceImpl) DeleteProvisionedDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
return dr.deleteDashboard(dashboardId, orgId, false) 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 { if validateProvisionedDashboard {
provisionedData, err := dr.GetProvisionedDashboardDataByDashboardID(dashboardId) provisionedData, err := dr.GetProvisionedDashboardDataByDashboardID(dashboardId)
if err != nil { if err != nil {
@@ -319,7 +319,7 @@ func (dr *dashboardServiceImpl) deleteDashboard(dashboardId int64, orgId int64,
} }
} }
cmd := &models.DeleteDashboardCommand{OrgId: orgId, Id: dashboardId} 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) ( 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) 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 { for index, dash := range s.SavedDashboards {
if dash.Dashboard.Id == dashboardId && dash.OrgId == orgId { if dash.Dashboard.Id == dashboardId && dash.OrgId == orgId {
s.SavedDashboards = append(s.SavedDashboards[:index], s.SavedDashboards[index+1:]...) s.SavedDashboards = append(s.SavedDashboards[:index], s.SavedDashboards[index+1:]...)

View File

@@ -237,14 +237,14 @@ func TestDashboardService(t *testing.T) {
t.Run("Given provisioned dashboard", func(t *testing.T) { t.Run("Given provisioned dashboard", func(t *testing.T) {
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) { t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) {
result := setupDeleteHandlers(t, &fakeStore, true) result := setupDeleteHandlers(t, &fakeStore, true)
err := service.DeleteProvisionedDashboard(1, 1) err := service.DeleteProvisionedDashboard(context.Background(), 1, 1)
require.NoError(t, err) require.NoError(t, err)
require.True(t, result.deleteWasCalled) require.True(t, result.deleteWasCalled)
}) })
t.Run("DeleteDashboard should fail to delete it", func(t *testing.T) { t.Run("DeleteDashboard should fail to delete it", func(t *testing.T) {
result := setupDeleteHandlers(t, &fakeStore, true) result := setupDeleteHandlers(t, &fakeStore, true)
err := service.DeleteDashboard(1, 1) err := service.DeleteDashboard(context.Background(), 1, 1)
require.Equal(t, err, models.ErrDashboardCannotDeleteProvisionedDashboard) require.Equal(t, err, models.ErrDashboardCannotDeleteProvisionedDashboard)
require.False(t, result.deleteWasCalled) require.False(t, result.deleteWasCalled)
}) })
@@ -254,13 +254,13 @@ func TestDashboardService(t *testing.T) {
result := setupDeleteHandlers(t, &fakeStore, false) result := setupDeleteHandlers(t, &fakeStore, false)
t.Run("DeleteProvisionedDashboard should delete it", func(t *testing.T) { 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.NoError(t, err)
require.True(t, result.deleteWasCalled) require.True(t, result.deleteWasCalled)
}) })
t.Run("DeleteDashboard should delete it", func(t *testing.T) { 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.NoError(t, err)
require.True(t, result.deleteWasCalled) require.True(t, result.deleteWasCalled)
}) })

View File

@@ -103,7 +103,7 @@ func (fr *FileReader) walkDisk(ctx context.Context) error {
return err return err
} }
fr.handleMissingDashboardFiles(provisionedDashboardRefs, filesFoundOnDisk) fr.handleMissingDashboardFiles(ctx, provisionedDashboardRefs, filesFoundOnDisk)
usageTracker := newUsageTracker() usageTracker := newUsageTracker()
if fr.FoldersFromFilesStructure { 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. // 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) { filesFoundOnDisk map[string]os.FileInfo) {
// find dashboards to delete since json file is missing // find dashboards to delete since json file is missing
var dashboardsToDelete []int64 var dashboardsToDelete []int64
@@ -209,7 +209,7 @@ func (fr *FileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[s
// delete dashboards missing JSON file // delete dashboards missing JSON file
for _, dashboardID := range dashboardsToDelete { for _, dashboardID := range dashboardsToDelete {
fr.log.Debug("deleting provisioned dashboard, missing on disk", "id", dashboardID) 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 { if err != nil {
fr.log.Error("failed to delete dashboard", "id", dashboardID, "error", err) fr.log.Error("failed to delete dashboard", "id", dashboardID, "error", err)
} }

View File

@@ -577,7 +577,7 @@ func (s *fakeDashboardProvisioningService) SaveProvisionedDashboard(ctx context.
if copyDto.Dashboard.Id == 0 { if copyDto.Dashboard.Id == 0 {
copyDto.Dashboard.Id = rand.Int63n(1000000) copyDto.Dashboard.Id = rand.Int63n(1000000)
} else { } 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 // Lets delete existing so we do not have duplicates
if err != nil { if err != nil {
return nil, err return nil, err
@@ -619,7 +619,7 @@ func (s *fakeDashboardProvisioningService) UnprovisionDashboard(dashboardID int6
return nil 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) err := s.UnprovisionDashboard(dashboardID)
if err != nil { if err != nil {
return err return err

View File

@@ -1,118 +1,126 @@
package sqlstore package sqlstore
import ( import (
"context"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
) )
func init() { func (ss *SQLStore) addPlaylistQueryAndCommandHandlers() {
bus.AddHandler("sql", CreatePlaylist) bus.AddHandlerCtx("sql", ss.CreatePlaylist)
bus.AddHandler("sql", UpdatePlaylist) bus.AddHandlerCtx("sql", ss.UpdatePlaylist)
bus.AddHandler("sql", DeletePlaylist) bus.AddHandlerCtx("sql", ss.DeletePlaylist)
bus.AddHandler("sql", SearchPlaylists) bus.AddHandlerCtx("sql", ss.SearchPlaylists)
bus.AddHandler("sql", GetPlaylist) bus.AddHandlerCtx("sql", ss.GetPlaylist)
bus.AddHandler("sql", GetPlaylistItem) bus.AddHandlerCtx("sql", ss.GetPlaylistItem)
} }
func CreatePlaylist(cmd *models.CreatePlaylistCommand) error { func (ss *SQLStore) CreatePlaylist(ctx context.Context, cmd *models.CreatePlaylistCommand) error {
playlist := models.Playlist{ return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
Name: cmd.Name, playlist := models.Playlist{
Interval: cmd.Interval, Name: cmd.Name,
OrgId: cmd.OrgId, Interval: cmd.Interval,
} OrgId: cmd.OrgId,
}
_, err := x.Insert(&playlist) _, err := sess.Insert(&playlist)
if err != nil { 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 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 { func (ss *SQLStore) UpdatePlaylist(ctx context.Context, cmd *models.UpdatePlaylistCommand) error {
playlist := models.Playlist{ return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
Id: cmd.Id, playlist := models.Playlist{
OrgId: cmd.OrgId, Id: cmd.Id,
Name: cmd.Name, OrgId: cmd.OrgId,
Interval: cmd.Interval, 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 { if existingPlaylist == nil {
return models.ErrPlaylistNotFound return models.ErrPlaylistNotFound
} }
cmd.Result = &models.PlaylistDTO{ cmd.Result = &models.PlaylistDTO{
Id: playlist.Id, Id: playlist.Id,
OrgId: playlist.OrgId, OrgId: playlist.OrgId,
Name: playlist.Name, Name: playlist.Name,
Interval: playlist.Interval, 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 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 { if query.Id == 0 {
return models.ErrCommandValidationFailed return models.ErrCommandValidationFailed
} }
playlist := models.Playlist{} return ss.WithDbSession(ctx, func(sess *DBSession) error {
_, err := x.ID(query.Id).Get(&playlist) 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 { if cmd.Id == 0 || cmd.OrgId == 0 {
return models.ErrCommandValidationFailed 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 = ?" var rawPlaylistSQL = "DELETE FROM playlist WHERE id = ? and org_id = ?"
_, err := sess.Exec(rawPlaylistSQL, cmd.Id, cmd.OrgId) _, err := sess.Exec(rawPlaylistSQL, cmd.Id, cmd.OrgId)
@@ -127,31 +135,35 @@ func DeletePlaylist(cmd *models.DeletePlaylistCommand) error {
}) })
} }
func SearchPlaylists(query *models.GetPlaylistsQuery) error { func (ss *SQLStore) SearchPlaylists(ctx context.Context, query *models.GetPlaylistsQuery) error {
var playlists = make(models.Playlists, 0) 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 != "" { if query.Name != "" {
sess.Where("name LIKE ?", "%"+query.Name+"%") sess.Where("name LIKE ?", "%"+query.Name+"%")
} }
sess.Where("org_id = ?", query.OrgId) sess.Where("org_id = ?", query.OrgId)
err := sess.Find(&playlists) err := sess.Find(&playlists)
query.Result = playlists query.Result = playlists
return err return err
})
} }
func GetPlaylistItem(query *models.GetPlaylistItemsByIdQuery) error { func (ss *SQLStore) GetPlaylistItem(ctx context.Context, query *models.GetPlaylistItemsByIdQuery) error {
if query.PlaylistId == 0 { return ss.WithDbSession(ctx, func(sess *DBSession) error {
return models.ErrCommandValidationFailed if query.PlaylistId == 0 {
} return models.ErrCommandValidationFailed
}
var playlistItems = make([]models.PlaylistItem, 0) var playlistItems = make([]models.PlaylistItem, 0)
err := x.Where("playlist_id=?", query.PlaylistId).Find(&playlistItems) err := sess.Where("playlist_id=?", query.PlaylistId).Find(&playlistItems)
query.Result = &playlistItems query.Result = &playlistItems
return err return err
})
} }

View File

@@ -4,6 +4,7 @@
package sqlstore package sqlstore
import ( import (
"context"
"testing" "testing"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
@@ -11,7 +12,7 @@ import (
) )
func TestPlaylistDataAccess(t *testing.T) { func TestPlaylistDataAccess(t *testing.T) {
InitTestDB(t) ss := InitTestDB(t)
t.Run("Can create playlist", func(t *testing.T) { t.Run("Can create playlist", func(t *testing.T) {
items := []models.PlaylistItemDTO{ items := []models.PlaylistItemDTO{
@@ -19,7 +20,7 @@ func TestPlaylistDataAccess(t *testing.T) {
{Title: "Backend response times", Value: "3", Type: "dashboard_by_id"}, {Title: "Backend response times", Value: "3", Type: "dashboard_by_id"},
} }
cmd := models.CreatePlaylistCommand{Name: "NYC office", Interval: "10m", OrgId: 1, Items: items} 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) require.NoError(t, err)
t.Run("Can update playlist", func(t *testing.T) { 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"}, {Title: "Backend response times", Value: "2", Type: "dashboard_by_id"},
} }
query := models.UpdatePlaylistCommand{Name: "NYC office ", OrgId: 1, Id: 1, Interval: "10s", Items: items} 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) require.NoError(t, err)
}) })
t.Run("Can remove playlist", func(t *testing.T) { t.Run("Can remove playlist", func(t *testing.T) {
deleteQuery := models.DeletePlaylistCommand{Id: 1, OrgId: 1} deleteQuery := models.DeletePlaylistCommand{Id: 1, OrgId: 1}
err = DeletePlaylist(&deleteQuery) err = ss.DeletePlaylist(context.Background(), &deleteQuery)
require.NoError(t, err) require.NoError(t, err)
getQuery := models.GetPlaylistByIdQuery{Id: 1} getQuery := models.GetPlaylistByIdQuery{Id: 1}
err = GetPlaylist(&getQuery) err = ss.GetPlaylist(context.Background(), &getQuery)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(0), getQuery.Result.Id, "playlist should've been removed") 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) { t.Run("Delete playlist that doesn't exist", func(t *testing.T) {
deleteQuery := models.DeletePlaylistCommand{Id: 1, OrgId: 1} deleteQuery := models.DeletePlaylistCommand{Id: 1, OrgId: 1}
err := DeletePlaylist(&deleteQuery) err := ss.DeletePlaylist(context.Background(), &deleteQuery)
require.NoError(t, err) require.NoError(t, err)
}) })
@@ -62,7 +63,7 @@ func TestPlaylistDataAccess(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) { 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()) require.EqualError(t, err, models.ErrCommandValidationFailed.Error())
}) })
} }

View File

@@ -121,6 +121,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
ss.addTempUserQueryAndCommandHandlers() ss.addTempUserQueryAndCommandHandlers()
ss.addDashboardVersionQueryAndCommandHandlers() ss.addDashboardVersionQueryAndCommandHandlers()
ss.addAPIKeysQueryAndCommandHandlers() ss.addAPIKeysQueryAndCommandHandlers()
ss.addPlaylistQueryAndCommandHandlers()
// if err := ss.Reset(); err != nil { // if err := ss.Reset(); err != nil {
// return nil, err // return nil, err