mirror of
https://github.com/grafana/grafana.git
synced 2024-12-25 08:21:46 -06:00
Instrument tracing across dashboards (#91937)
Add tracing across dashboards and accesscontrol
This commit is contained in:
parent
ce64d79027
commit
372d0acec8
@ -46,8 +46,11 @@ import (
|
||||
publicdashboardsapi "github.com/grafana/grafana/pkg/services/publicdashboards/api"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/api")
|
||||
|
||||
// registerRoutes registers all API HTTP routes.
|
||||
func (hs *HTTPServer) registerRoutes() {
|
||||
reqNoAuth := middleware.NoAuth()
|
||||
|
@ -40,6 +40,10 @@ const (
|
||||
)
|
||||
|
||||
func (hs *HTTPServer) isDashboardStarredByUser(c *contextmodel.ReqContext, dashID int64) (bool, error) {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.isDashboardStarredByUser")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
if !c.IsSignedIn {
|
||||
return false, nil
|
||||
}
|
||||
@ -81,8 +85,9 @@ func dashboardGuardianResponse(err error) response.Response {
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := hs.tracer.Start(c.Req.Context(), "api.GetDashboard")
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
dash, rsp := hs.getDashboardHelper(ctx, c.SignedInUser.GetOrgID(), 0, uid)
|
||||
@ -230,6 +235,10 @@ func (hs *HTTPServer) GetDashboard(c *contextmodel.ReqContext) response.Response
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getAnnotationPermissionsByScope(c *contextmodel.ReqContext, actions *dashboardsV0.AnnotationActions, scope string) {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.getAnnotationPermissionsByScope")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var err error
|
||||
|
||||
evaluate := accesscontrol.EvalPermission(accesscontrol.ActionAnnotationsCreate, scope)
|
||||
@ -252,6 +261,9 @@ func (hs *HTTPServer) getAnnotationPermissionsByScope(c *contextmodel.ReqContext
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getUserLogin(ctx context.Context, userID int64) string {
|
||||
ctx, span := tracer.Start(ctx, "api.getUserLogin")
|
||||
defer span.End()
|
||||
|
||||
query := user.GetUserByIDQuery{ID: userID}
|
||||
user, err := hs.userService.GetByID(ctx, &query)
|
||||
if err != nil {
|
||||
@ -292,6 +304,10 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) RestoreDeletedDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.RestoreDeletedDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
cmd := dashboards.RestoreDeletedDashboardCommand{}
|
||||
|
||||
@ -342,6 +358,10 @@ func (hs *HTTPServer) RestoreDeletedDashboard(c *contextmodel.ReqContext) respon
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) SoftDeleteDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.SoftDeleteDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
dash, rsp := hs.getDashboardHelper(c.Req.Context(), c.SignedInUser.GetOrgID(), 0, uid)
|
||||
if rsp != nil {
|
||||
@ -408,6 +428,10 @@ func (hs *HTTPServer) HardDeleteDashboardByUID(c *contextmodel.ReqContext) respo
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.deleteDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
uid := web.Params(c.Req)[":uid"]
|
||||
|
||||
var dash *dashboards.Dashboard
|
||||
@ -496,6 +520,10 @@ func (hs *HTTPServer) deleteDashboard(c *contextmodel.ReqContext) response.Respo
|
||||
// 422: unprocessableEntityError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) PostDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.PostDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
cmd := dashboards.SaveDashboardCommand{}
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
@ -504,11 +532,15 @@ func (hs *HTTPServer) PostDashboard(c *contextmodel.ReqContext) response.Respons
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.SaveDashboardCommand) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.postDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
if cmd.IsFolder {
|
||||
return response.Error(http.StatusBadRequest, "Use folders endpoint for saving folders.", nil)
|
||||
}
|
||||
|
||||
ctx := c.Req.Context()
|
||||
ctx = c.Req.Context()
|
||||
var err error
|
||||
|
||||
var userID int64
|
||||
@ -622,6 +654,10 @@ func (hs *HTTPServer) postDashboard(c *contextmodel.ReqContext, cmd dashboards.S
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetHomeDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var userID int64
|
||||
if id, err := identity.UserIdentifier(c.SignedInUser.GetID()); err == nil {
|
||||
userID = id
|
||||
@ -685,6 +721,10 @@ func (hs *HTTPServer) GetHomeDashboard(c *contextmodel.ReqContext) response.Resp
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *contextmodel.ReqContext, dash *simplejson.Json) {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.addGettingStartedPanelToHomeDashboard")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
// We only add this getting started panel for Admins who have not dismissed it,
|
||||
// and if a custom default home dashboard hasn't been configured
|
||||
if !c.HasUserRole(org.RoleAdmin) ||
|
||||
@ -736,6 +776,10 @@ func (hs *HTTPServer) addGettingStartedPanelToHomeDashboard(c *contextmodel.ReqC
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardVersions")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var dashID int64
|
||||
|
||||
var err error
|
||||
@ -846,6 +890,10 @@ func (hs *HTTPServer) GetDashboardVersions(c *contextmodel.ReqContext) response.
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardVersion")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var dashID int64
|
||||
|
||||
var err error
|
||||
@ -921,6 +969,10 @@ func (hs *HTTPServer) GetDashboardVersion(c *contextmodel.ReqContext) response.R
|
||||
// 403: forbiddenError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.CalculateDashboardDiff")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
apiOptions := dtos.CalculateDiffOptions{}
|
||||
if err := web.Bind(c.Req, &apiOptions); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||
@ -1032,6 +1084,10 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *contextmodel.ReqContext) respons
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.RestoreDashboardVersion")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var dashID int64
|
||||
|
||||
var err error
|
||||
@ -1098,6 +1154,10 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *contextmodel.ReqContext) respon
|
||||
// 401: unauthorisedError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardTags")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
query := dashboards.GetDashboardTagsQuery{OrgID: c.SignedInUser.GetOrgID()}
|
||||
queryResult, err := hs.DashboardService.GetDashboardTags(c.Req.Context(), &query)
|
||||
if err != nil {
|
||||
@ -1110,6 +1170,10 @@ func (hs *HTTPServer) GetDashboardTags(c *contextmodel.ReqContext) {
|
||||
|
||||
// GetDashboardUIDs converts internal ids to UIDs
|
||||
func (hs *HTTPServer) GetDashboardUIDs(c *contextmodel.ReqContext) {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardUIDs")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
ids := strings.Split(web.Params(c.Req)[":ids"], ",")
|
||||
uids := make([]string, 0, len(ids))
|
||||
|
||||
|
@ -44,6 +44,10 @@ import (
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) GetDashboardPermissionList(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.GetDashboardPermissionList")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var dashID int64
|
||||
var err error
|
||||
dashUID := web.Params(c.Req)[":uid"]
|
||||
@ -117,6 +121,10 @@ func (hs *HTTPServer) GetDashboardPermissionList(c *contextmodel.ReqContext) res
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (hs *HTTPServer) UpdateDashboardPermissions(c *contextmodel.ReqContext) response.Response {
|
||||
ctx, span := tracer.Start(c.Req.Context(), "api.UpdateDashboardPermissions")
|
||||
defer span.End()
|
||||
c.Req = c.Req.WithContext(ctx)
|
||||
|
||||
var dashID int64
|
||||
var err error
|
||||
apiCmd := dtos.UpdateDashboardACLCommand{}
|
||||
@ -175,6 +183,9 @@ var dashboardPermissionMap = map[string]dashboardaccess.PermissionType{
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getDashboardACL(ctx context.Context, user identity.Requester, dashboard *dashboards.Dashboard) ([]*dashboards.DashboardACLInfoDTO, error) {
|
||||
ctx, span := tracer.Start(ctx, "api.getDashboardACL")
|
||||
defer span.End()
|
||||
|
||||
permissions, err := hs.dashboardPermissionsService.GetPermissions(ctx, user, dashboard.UID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -253,6 +264,9 @@ func (hs *HTTPServer) filterHiddenACL(user identity.Requester, acl []*dashboards
|
||||
|
||||
// updateDashboardAccessControl is used for api backward compatibility
|
||||
func (hs *HTTPServer) updateDashboardAccessControl(ctx context.Context, orgID int64, uid string, isFolder bool, items []*dashboards.DashboardACL, old []*dashboards.DashboardACLInfoDTO) error {
|
||||
ctx, span := tracer.Start(ctx, "api.updateDashboardAccessControl")
|
||||
defer span.End()
|
||||
|
||||
commands := []accesscontrol.SetResourcePermissionCommand{}
|
||||
for _, item := range items {
|
||||
permissions := item.Permission.String()
|
||||
|
@ -50,8 +50,7 @@ func (api *AccessControlAPI) getUserActions(c *contextmodel.ReqContext) response
|
||||
defer span.End()
|
||||
|
||||
reloadCache := c.QueryBool("reloadcache")
|
||||
permissions, err := api.Service.GetUserPermissions(ctx,
|
||||
c.SignedInUser, ac.Options{ReloadCache: reloadCache})
|
||||
permissions, err := api.Service.GetUserPermissions(ctx, c.SignedInUser, ac.Options{ReloadCache: reloadCache})
|
||||
if err != nil {
|
||||
return response.JSON(http.StatusInternalServerError, err)
|
||||
}
|
||||
@ -65,8 +64,7 @@ func (api *AccessControlAPI) getUserPermissions(c *contextmodel.ReqContext) resp
|
||||
defer span.End()
|
||||
|
||||
reloadCache := c.QueryBool("reloadcache")
|
||||
permissions, err := api.Service.GetUserPermissions(ctx,
|
||||
c.SignedInUser, ac.Options{ReloadCache: reloadCache})
|
||||
permissions, err := api.Service.GetUserPermissions(ctx, c.SignedInUser, ac.Options{ReloadCache: reloadCache})
|
||||
if err != nil {
|
||||
return response.JSON(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ type Service struct {
|
||||
}
|
||||
|
||||
func (s *Service) GetPermissions(ctx context.Context, user identity.Requester, resourceID string) ([]accesscontrol.ResourcePermission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.GetPermissions")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.GetPermissions")
|
||||
defer span.End()
|
||||
|
||||
var inheritedScopes []string
|
||||
@ -209,7 +209,7 @@ func (s *Service) GetPermissions(ctx context.Context, user identity.Requester, r
|
||||
}
|
||||
|
||||
func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user accesscontrol.User, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetUserPermission")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetUserPermission")
|
||||
defer span.End()
|
||||
|
||||
actions, err := s.mapPermission(permission)
|
||||
@ -235,7 +235,7 @@ func (s *Service) SetUserPermission(ctx context.Context, orgID int64, user acces
|
||||
}
|
||||
|
||||
func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetTeamPermission")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetTeamPermission")
|
||||
defer span.End()
|
||||
|
||||
actions, err := s.mapPermission(permission)
|
||||
@ -261,7 +261,7 @@ func (s *Service) SetTeamPermission(ctx context.Context, orgID, teamID int64, re
|
||||
}
|
||||
|
||||
func (s *Service) SetBuiltInRolePermission(ctx context.Context, orgID int64, builtInRole, resourceID, permission string) (*accesscontrol.ResourcePermission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetBuiltInRolePermission")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetBuiltInRolePermission")
|
||||
defer span.End()
|
||||
|
||||
actions, err := s.mapPermission(permission)
|
||||
@ -290,7 +290,7 @@ func (s *Service) SetPermissions(
|
||||
ctx context.Context, orgID int64, resourceID string,
|
||||
commands ...accesscontrol.SetResourcePermissionCommand,
|
||||
) ([]accesscontrol.ResourcePermission, error) {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.SetPermissions")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.SetPermissions")
|
||||
defer span.End()
|
||||
|
||||
if err := s.validateResource(ctx, orgID, resourceID); err != nil {
|
||||
@ -370,7 +370,7 @@ func (s *Service) mapPermission(permission string) ([]string, error) {
|
||||
}
|
||||
|
||||
func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID string) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateResource")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateResource")
|
||||
defer span.End()
|
||||
|
||||
if s.options.ResourceValidator != nil {
|
||||
@ -380,7 +380,7 @@ func (s *Service) validateResource(ctx context.Context, orgID int64, resourceID
|
||||
}
|
||||
|
||||
func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateUser")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateUser")
|
||||
defer span.End()
|
||||
|
||||
if !s.options.Assignments.Users {
|
||||
@ -397,7 +397,7 @@ func (s *Service) validateUser(ctx context.Context, orgID, userID int64) error {
|
||||
}
|
||||
|
||||
func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateTeam")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateTeam")
|
||||
defer span.End()
|
||||
|
||||
if !s.options.Assignments.Teams {
|
||||
@ -416,7 +416,7 @@ func (s *Service) validateTeam(ctx context.Context, orgID, teamID int64) error {
|
||||
}
|
||||
|
||||
func (s *Service) validateBuiltinRole(ctx context.Context, builtinRole string) error {
|
||||
_, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.validateBuiltinRole")
|
||||
_, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.validateBuiltinRole")
|
||||
defer span.End()
|
||||
|
||||
if !s.options.Assignments.BuiltInRoles {
|
||||
@ -580,7 +580,7 @@ func (a *ActionSetSvc) ExpandActionSetsWithFilter(permissions []accesscontrol.Pe
|
||||
// RegisterActionSets allow the caller to expand the existing action sets with additional permissions
|
||||
// This is intended to be used by plugins, and currently supports extending folder and dashboard action sets
|
||||
func (a *ActionSetSvc) RegisterActionSets(ctx context.Context, pluginID string, registrations []plugins.ActionSet) error {
|
||||
ctx, span := tracer.Start(ctx, "accesscontroll.resourcepermissions.RegisterActionSets")
|
||||
ctx, span := tracer.Start(ctx, "accesscontrol.resourcepermissions.RegisterActionSets")
|
||||
defer span.End()
|
||||
|
||||
if !a.features.IsEnabled(ctx, featuremgmt.FlagAccessActionSets) || !a.features.IsEnabled(ctx, featuremgmt.FlagAccessControlOnCall) {
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -38,12 +39,16 @@ var (
|
||||
ScopeFoldersAll = ScopeFoldersProvider.GetResourceAllScope()
|
||||
ScopeDashboardsProvider = ac.NewScopeProvider(ScopeDashboardsRoot)
|
||||
ScopeDashboardsAll = ScopeDashboardsProvider.GetResourceAllScope()
|
||||
tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboards")
|
||||
)
|
||||
|
||||
// NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope.
|
||||
func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScopeName("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.NewFolderNameScopeResolver")
|
||||
span.End()
|
||||
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
return nil, ac.ErrInvalidScope
|
||||
}
|
||||
@ -72,6 +77,9 @@ func NewFolderNameScopeResolver(folderDB folder.FolderStore, folderSvc folder.Se
|
||||
func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScope("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.NewFolderIDScopeResolver")
|
||||
span.End()
|
||||
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
return nil, ac.ErrInvalidScope
|
||||
}
|
||||
@ -105,6 +113,9 @@ func NewFolderIDScopeResolver(folderDB folder.FolderStore, folderSvc folder.Serv
|
||||
func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeFoldersProvider.GetResourceScopeUID("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.NewFolderUIDScopeResolver")
|
||||
span.End()
|
||||
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
return nil, ac.ErrInvalidScope
|
||||
}
|
||||
@ -127,6 +138,9 @@ func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttrib
|
||||
func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeDashboardsProvider.GetResourceScope("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.NewDashboardIDScopeResolver")
|
||||
span.End()
|
||||
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
return nil, ac.ErrInvalidScope
|
||||
}
|
||||
@ -150,6 +164,9 @@ func NewDashboardIDScopeResolver(folderDB folder.FolderStore, ds DashboardServic
|
||||
func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
|
||||
prefix := ScopeDashboardsProvider.GetResourceScopeUID("")
|
||||
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.NewDashboardUIDScopeResolver")
|
||||
span.End()
|
||||
|
||||
if !strings.HasPrefix(scope, prefix) {
|
||||
return nil, ac.ErrInvalidScope
|
||||
}
|
||||
@ -169,6 +186,9 @@ func NewDashboardUIDScopeResolver(folderDB folder.FolderStore, ds DashboardServi
|
||||
}
|
||||
|
||||
func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.resolveDashboardScope")
|
||||
span.End()
|
||||
|
||||
var folderUID string
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
|
||||
// nolint:staticcheck
|
||||
@ -204,6 +224,9 @@ func resolveDashboardScope(ctx context.Context, folderDB folder.FolderStore, org
|
||||
}
|
||||
|
||||
func GetInheritedScopes(ctx context.Context, orgID int64, folderUID string, folderSvc folder.Service) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.GetInheritedScopes")
|
||||
span.End()
|
||||
|
||||
if folderUID == ac.GeneralFolderUID {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -25,8 +25,11 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/tag"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboard/database")
|
||||
|
||||
type dashboardStore struct {
|
||||
store db.ReplDB
|
||||
cfg *setting.Cfg
|
||||
@ -69,6 +72,9 @@ func (d *dashboardStore) emitEntityEvent() bool {
|
||||
}
|
||||
|
||||
func (d *dashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dashboard *dashboards.Dashboard, overwrite bool) (bool, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.ValidateDashboardBeforesave")
|
||||
defer span.End()
|
||||
|
||||
isParentFolderChanged := false
|
||||
err := d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
var err error
|
||||
@ -93,6 +99,9 @@ func (d *dashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dashbo
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetProvisionedDataByDashboardID(ctx context.Context, dashboardID int64) (*dashboards.DashboardProvisioning, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetProvisionedDataByDashboardID")
|
||||
defer span.End()
|
||||
|
||||
var data dashboards.DashboardProvisioning
|
||||
err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
_, err := sess.Where("dashboard_id = ?", dashboardID).Get(&data)
|
||||
@ -106,6 +115,9 @@ func (d *dashboardStore) GetProvisionedDataByDashboardID(ctx context.Context, da
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetProvisionedDataByDashboardUID(ctx context.Context, orgID int64, dashboardUID string) (*dashboards.DashboardProvisioning, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetProvisionedDataByDashboardUID")
|
||||
defer span.End()
|
||||
|
||||
var provisionedDashboard dashboards.DashboardProvisioning
|
||||
err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
var dashboard dashboards.Dashboard
|
||||
@ -129,6 +141,9 @@ func (d *dashboardStore) GetProvisionedDataByDashboardUID(ctx context.Context, o
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetProvisionedDashboardData(ctx context.Context, name string) ([]*dashboards.DashboardProvisioning, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetProvisionedDashboardData")
|
||||
defer span.End()
|
||||
|
||||
var result []*dashboards.DashboardProvisioning
|
||||
err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return sess.Where("name = ?", name).Find(&result)
|
||||
@ -137,6 +152,9 @@ func (d *dashboardStore) GetProvisionedDashboardData(ctx context.Context, name s
|
||||
}
|
||||
|
||||
func (d *dashboardStore) SaveProvisionedDashboard(ctx context.Context, cmd dashboards.SaveDashboardCommand, provisioning *dashboards.DashboardProvisioning) (*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.SaveProvisionedDashboard")
|
||||
defer span.End()
|
||||
|
||||
var result *dashboards.Dashboard
|
||||
var err error
|
||||
err = d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
@ -155,6 +173,9 @@ func (d *dashboardStore) SaveProvisionedDashboard(ctx context.Context, cmd dashb
|
||||
}
|
||||
|
||||
func (d *dashboardStore) SaveDashboard(ctx context.Context, cmd dashboards.SaveDashboardCommand) (*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.SaveDashboard")
|
||||
defer span.End()
|
||||
|
||||
var result *dashboards.Dashboard
|
||||
var err error
|
||||
err = d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
@ -173,6 +194,9 @@ func (d *dashboardStore) SaveDashboard(ctx context.Context, cmd dashboards.SaveD
|
||||
// UnprovisionDashboard removes row in dashboard_provisioning for the dashboard making it seem as if manually created.
|
||||
// The dashboard will still have `created_by = -1` to see it was not created by any particular user.
|
||||
func (d *dashboardStore) UnprovisionDashboard(ctx context.Context, id int64) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.UnprovisionDashboard")
|
||||
defer span.End()
|
||||
|
||||
return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
_, err := sess.Where("dashboard_id = ?", id).Delete(&dashboards.DashboardProvisioning{})
|
||||
return err
|
||||
@ -180,6 +204,9 @@ func (d *dashboardStore) UnprovisionDashboard(ctx context.Context, id int64) err
|
||||
}
|
||||
|
||||
func (d *dashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *dashboards.DeleteOrphanedProvisionedDashboardsCommand) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.DeleteOrphanedProvisionedDashboards")
|
||||
defer span.End()
|
||||
|
||||
return d.store.DB().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
var result []*dashboards.DashboardProvisioning
|
||||
|
||||
@ -205,6 +232,9 @@ func (d *dashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context
|
||||
}
|
||||
|
||||
func (d *dashboardStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.Count")
|
||||
defer span.End()
|
||||
|
||||
u := "a.Map{}
|
||||
type result struct {
|
||||
Count int64
|
||||
@ -500,6 +530,9 @@ func saveProvisionedData(sess *db.Session, provisioning *dashboards.DashboardPro
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetDashboardsByPluginID(ctx context.Context, query *dashboards.GetDashboardsByPluginIDQuery) ([]*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboardsByPluginID")
|
||||
defer span.End()
|
||||
|
||||
var dashboards = make([]*dashboards.Dashboard, 0)
|
||||
err := d.store.DB().WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
whereExpr := "org_id=? AND plugin_id=? AND is_folder=" + d.store.DB().GetDialect().BooleanStr(false)
|
||||
@ -514,6 +547,9 @@ func (d *dashboardStore) GetDashboardsByPluginID(ctx context.Context, query *das
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetSoftDeletedDashboard(ctx context.Context, orgID int64, uid string) (*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetSoftDeletedDashboard")
|
||||
defer span.End()
|
||||
|
||||
if orgID == 0 || uid == "" {
|
||||
return nil, dashboards.ErrDashboardIdentifierNotSet
|
||||
}
|
||||
@ -537,6 +573,9 @@ func (d *dashboardStore) GetSoftDeletedDashboard(ctx context.Context, orgID int6
|
||||
}
|
||||
|
||||
func (d *dashboardStore) RestoreDashboard(ctx context.Context, orgID int64, dashboardUID string, folder *folder.Folder) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.RestoreDashboard")
|
||||
defer span.End()
|
||||
|
||||
return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
if folder == nil || folder.UID == "" {
|
||||
_, err := sess.Exec("UPDATE dashboard SET deleted=NULL, folder_id=0, folder_uid=NULL WHERE org_id=? AND uid=?", orgID, dashboardUID)
|
||||
@ -549,6 +588,9 @@ func (d *dashboardStore) RestoreDashboard(ctx context.Context, orgID int64, dash
|
||||
}
|
||||
|
||||
func (d *dashboardStore) SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUID string) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.SoftDeleteDashboard")
|
||||
defer span.End()
|
||||
|
||||
return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
_, err := sess.Exec("UPDATE dashboard SET deleted=? WHERE org_id=? AND uid=?", time.Now(), orgID, dashboardUID)
|
||||
return err
|
||||
@ -556,6 +598,9 @@ func (d *dashboardStore) SoftDeleteDashboard(ctx context.Context, orgID int64, d
|
||||
}
|
||||
|
||||
func (d *dashboardStore) SoftDeleteDashboardsInFolders(ctx context.Context, orgID int64, folderUids []string) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.SoftDeleteDashboardsInFolders")
|
||||
defer span.End()
|
||||
|
||||
if len(folderUids) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -580,6 +625,9 @@ func (d *dashboardStore) SoftDeleteDashboardsInFolders(ctx context.Context, orgI
|
||||
}
|
||||
|
||||
func (d *dashboardStore) DeleteDashboard(ctx context.Context, cmd *dashboards.DeleteDashboardCommand) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.DeleteDashboard")
|
||||
defer span.End()
|
||||
|
||||
return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
return d.deleteDashboard(cmd, sess, d.emitEntityEvent())
|
||||
})
|
||||
@ -736,6 +784,9 @@ func createEntityEvent(dashboard *dashboards.Dashboard, eventType store.EntityEv
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.GetDashboardQuery) (*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboard")
|
||||
defer span.End()
|
||||
|
||||
var queryResult *dashboards.Dashboard
|
||||
err := d.store.ReadReplica().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Dashboard).Inc()
|
||||
@ -778,6 +829,9 @@ func (d *dashboardStore) GetDashboard(ctx context.Context, query *dashboards.Get
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetDashboardUIDByID(ctx context.Context, query *dashboards.GetDashboardRefByIDQuery) (*dashboards.DashboardRef, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboardUIDByID")
|
||||
defer span.End()
|
||||
|
||||
us := &dashboards.DashboardRef{}
|
||||
err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
var rawSQL = `SELECT uid, slug from dashboard WHERE Id=?`
|
||||
@ -796,6 +850,9 @@ func (d *dashboardStore) GetDashboardUIDByID(ctx context.Context, query *dashboa
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetDashboards(ctx context.Context, query *dashboards.GetDashboardsQuery) ([]*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboards")
|
||||
defer span.End()
|
||||
|
||||
var dashboards = make([]*dashboards.Dashboard, 0)
|
||||
err := d.store.ReadReplica().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
if len(query.DashboardIDs) == 0 && len(query.DashboardUIDs) == 0 {
|
||||
@ -824,6 +881,9 @@ func (d *dashboardStore) GetDashboards(ctx context.Context, query *dashboards.Ge
|
||||
}
|
||||
|
||||
func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.FindDashboards")
|
||||
defer span.End()
|
||||
|
||||
recursiveQueriesAreSupported, err := d.store.ReadReplica().RecursiveQueriesAreSupported()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -914,6 +974,9 @@ func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.F
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) ([]*dashboards.DashboardTagCloudItem, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetDashboardTags")
|
||||
defer span.End()
|
||||
|
||||
queryResult := make([]*dashboards.DashboardTagCloudItem, 0)
|
||||
err := d.store.DB().WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
sql := `SELECT
|
||||
@ -939,6 +1002,9 @@ func (d *dashboardStore) GetDashboardTags(ctx context.Context, query *dashboards
|
||||
// given parent folder ID.
|
||||
func (d *dashboardStore) CountDashboardsInFolders(
|
||||
ctx context.Context, req *dashboards.CountDashboardsInFolderRequest) (int64, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.CountDashboardsInFolders")
|
||||
defer span.End()
|
||||
|
||||
if len(req.FolderUIDs) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
@ -967,6 +1033,9 @@ func (d *dashboardStore) CountDashboardsInFolders(
|
||||
|
||||
func (d *dashboardStore) DeleteDashboardsInFolders(
|
||||
ctx context.Context, req *dashboards.DeleteDashboardsInFolderRequest) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.DeleteDashboardsInFolders")
|
||||
defer span.End()
|
||||
|
||||
return d.store.DB().WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||
// TODO delete all dashboards in the folder in a bulk query
|
||||
for _, folderUID := range req.FolderUIDs {
|
||||
@ -993,6 +1062,9 @@ func (d *dashboardStore) DeleteDashboardsInFolders(
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetAllDashboards(ctx context.Context) ([]*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetAllDashboards")
|
||||
defer span.End()
|
||||
|
||||
var dashboards = make([]*dashboards.Dashboard, 0)
|
||||
err := d.store.ReadReplica().WithDbSession(ctx, func(session *db.Session) error {
|
||||
err := session.Find(&dashboards)
|
||||
@ -1005,6 +1077,9 @@ func (d *dashboardStore) GetAllDashboards(ctx context.Context) ([]*dashboards.Da
|
||||
}
|
||||
|
||||
func (d *dashboardStore) GetSoftDeletedExpiredDashboards(ctx context.Context, duration time.Duration) ([]*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.GetSoftDeletedExpiredDashboards")
|
||||
defer span.End()
|
||||
|
||||
var dashboards = make([]*dashboards.Dashboard, 0)
|
||||
err := d.store.DB().WithDbSession(ctx, func(sess *db.Session) error {
|
||||
err := sess.Where("deleted IS NOT NULL AND deleted < ?", time.Now().Add(-duration)).Find(&dashboards)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/grafana/authlib/claims"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
@ -43,6 +44,7 @@ var (
|
||||
_ dashboards.PluginService = (*DashboardServiceImpl)(nil)
|
||||
|
||||
daysInTrash = 24 * 30 * time.Hour
|
||||
tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/dashboards/service")
|
||||
)
|
||||
|
||||
type DashboardServiceImpl struct {
|
||||
@ -103,6 +105,9 @@ func (dr *DashboardServiceImpl) GetProvisionedDashboardDataByDashboardUID(ctx co
|
||||
//nolint:gocyclo
|
||||
func (dr *DashboardServiceImpl) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards.SaveDashboardDTO,
|
||||
validateProvisionedDashboard bool) (*dashboards.SaveDashboardCommand, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.BuildSaveDashboardcommand")
|
||||
defer span.End()
|
||||
|
||||
dash := dto.Dashboard
|
||||
|
||||
dash.OrgID = dto.OrgID
|
||||
@ -242,6 +247,9 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context.
|
||||
// getGuardianForSavePermissionCheck returns the guardian to be used for checking permission of dashboard
|
||||
// It replaces deleted Dashboard.GetDashboardIdForSavePermissionCheck()
|
||||
func getGuardianForSavePermissionCheck(ctx context.Context, d *dashboards.Dashboard, user identity.Requester) (guardian.DashboardGuardian, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.getGuardianForSavePermissionCheck")
|
||||
defer span.End()
|
||||
|
||||
newDashboard := d.ID == 0
|
||||
|
||||
if newDashboard {
|
||||
@ -290,6 +298,9 @@ func validateDashboardRefreshInterval(minRefreshInterval string, dash *dashboard
|
||||
|
||||
func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO,
|
||||
provisioning *dashboards.DashboardProvisioning) (*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.SaveProvisionedDashboard")
|
||||
defer span.End()
|
||||
|
||||
if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil {
|
||||
dr.log.Warn("Changing refresh interval for provisioned dashboard to minimum refresh interval", "dashboardUid",
|
||||
dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval", dr.cfg.MinRefreshInterval)
|
||||
@ -317,6 +328,9 @@ func (dr *DashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dt
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.Context, dto *folder.CreateFolderCommand) (*folder.Folder, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.SaveFolderForProvisionedDashboards")
|
||||
defer span.End()
|
||||
|
||||
dto.SignedInUser = accesscontrol.BackgroundUser("dashboard_provisioning", dto.OrgID, org.RoleAdmin, provisionerPermissions)
|
||||
f, err := dr.folderService.Create(ctx, dto)
|
||||
if err != nil {
|
||||
@ -330,6 +344,9 @@ func (dr *DashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.C
|
||||
|
||||
func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO,
|
||||
allowUiUpdate bool) (*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.SaveDashboard")
|
||||
defer span.End()
|
||||
|
||||
if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil {
|
||||
dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval",
|
||||
"dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title, "minRefreshInterval",
|
||||
@ -359,6 +376,9 @@ func (dr *DashboardServiceImpl) GetSoftDeletedDashboard(ctx context.Context, org
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) RestoreDashboard(ctx context.Context, dashboard *dashboards.Dashboard, user identity.Requester, optionalFolderUID string) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.RestoreDashboard")
|
||||
defer span.End()
|
||||
|
||||
if !dr.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
return fmt.Errorf("feature flag %s is not enabled", featuremgmt.FlagDashboardRestore)
|
||||
}
|
||||
@ -398,6 +418,9 @@ func (dr *DashboardServiceImpl) RestoreDashboard(ctx context.Context, dashboard
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) SoftDeleteDashboard(ctx context.Context, orgID int64, dashboardUID string) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.SoftDeleteDashboard")
|
||||
defer span.End()
|
||||
|
||||
if !dr.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
return fmt.Errorf("feature flag %s is not enabled", featuremgmt.FlagDashboardRestore)
|
||||
}
|
||||
@ -426,6 +449,9 @@ func (dr *DashboardServiceImpl) DeleteProvisionedDashboard(ctx context.Context,
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId int64, orgId int64, validateProvisionedDashboard bool) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.deleteDashboard")
|
||||
defer span.End()
|
||||
|
||||
if validateProvisionedDashboard {
|
||||
provisionedData, err := dr.GetProvisionedDashboardDataByDashboardID(ctx, dashboardId)
|
||||
if err != nil {
|
||||
@ -442,6 +468,9 @@ func (dr *DashboardServiceImpl) deleteDashboard(ctx context.Context, dashboardId
|
||||
|
||||
func (dr *DashboardServiceImpl) ImportDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO) (
|
||||
*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.ImportDashboard")
|
||||
defer span.End()
|
||||
|
||||
if err := validateDashboardRefreshInterval(dr.cfg.MinRefreshInterval, dto.Dashboard); err != nil {
|
||||
dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval",
|
||||
"dashboardUid", dto.Dashboard.UID, "dashboardTitle", dto.Dashboard.Title,
|
||||
@ -475,6 +504,9 @@ func (dr *DashboardServiceImpl) GetDashboardsByPluginID(ctx context.Context, que
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *dashboards.SaveDashboardDTO, dash *dashboards.Dashboard, provisioned bool) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.setDefaultPermissions")
|
||||
defer span.End()
|
||||
|
||||
resource := "dashboard"
|
||||
if dash.IsFolder {
|
||||
resource = "folder"
|
||||
@ -518,6 +550,9 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto *
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) setDefaultFolderPermissions(ctx context.Context, cmd *folder.CreateFolderCommand, f *folder.Folder, provisioned bool) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.setDefaultFolderPermissions")
|
||||
defer span.End()
|
||||
|
||||
if !dr.cfg.RBAC.PermissionsOnCreation("folder") {
|
||||
return
|
||||
}
|
||||
@ -565,6 +600,9 @@ func (dr *DashboardServiceImpl) GetDashboardsSharedWithUser(ctx context.Context,
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) getDashboardsSharedWithUser(ctx context.Context, user identity.Requester) ([]*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.getDashboardsSharedWithUser")
|
||||
defer span.End()
|
||||
|
||||
permissions := user.GetPermissions()
|
||||
dashboardPermissions := permissions[dashboards.ActionDashboardsRead]
|
||||
sharedDashboards := make([]*dashboards.Dashboard, 0)
|
||||
@ -594,6 +632,9 @@ func (dr *DashboardServiceImpl) getDashboardsSharedWithUser(ctx context.Context,
|
||||
|
||||
// filterUserSharedDashboards filter dashboards directly assigned to user, but not located in folders with view permissions
|
||||
func (dr *DashboardServiceImpl) filterUserSharedDashboards(ctx context.Context, user identity.Requester, userDashboards []*dashboards.Dashboard) ([]*dashboards.Dashboard, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.filterUserSharedDashboards")
|
||||
defer span.End()
|
||||
|
||||
filteredDashboards := make([]*dashboards.Dashboard, 0)
|
||||
|
||||
folderUIDs := make([]string, 0)
|
||||
@ -632,6 +673,9 @@ func (dr *DashboardServiceImpl) filterUserSharedDashboards(ctx context.Context,
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) getUserSharedDashboardUIDs(ctx context.Context, user identity.Requester) ([]string, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.getUserSharedDashboardsUIDs")
|
||||
defer span.End()
|
||||
|
||||
userDashboards, err := dr.getDashboardsSharedWithUser(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -644,6 +688,9 @@ func (dr *DashboardServiceImpl) getUserSharedDashboardUIDs(ctx context.Context,
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.FindDashboards")
|
||||
defer span.End()
|
||||
|
||||
if dr.features.IsEnabled(ctx, featuremgmt.FlagNestedFolders) && len(query.FolderUIDs) > 0 && slices.Contains(query.FolderUIDs, folder.SharedWithMeFolderUID) {
|
||||
start := time.Now()
|
||||
userDashboardUIDs, err := dr.getUserSharedDashboardUIDs(ctx, query.SignedInUser)
|
||||
@ -665,6 +712,9 @@ func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashb
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) SearchDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) (model.HitList, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.SearchDashboards")
|
||||
defer span.End()
|
||||
|
||||
res, err := dr.FindDashboards(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -745,6 +795,9 @@ func (dr DashboardServiceImpl) CountInFolders(ctx context.Context, orgID int64,
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64, folderUIDs []string, u identity.Requester) error {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.DeleteInFolders")
|
||||
defer span.End()
|
||||
|
||||
if dr.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
return dr.dashboardStore.SoftDeleteDashboardsInFolders(ctx, orgID, folderUIDs)
|
||||
}
|
||||
@ -755,6 +808,9 @@ func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64
|
||||
func (dr *DashboardServiceImpl) Kind() string { return entity.StandardKindDashboard }
|
||||
|
||||
func (dr *DashboardServiceImpl) CleanUpDeletedDashboards(ctx context.Context) (int64, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.service.CleanUpDeletedDashboards")
|
||||
defer span.End()
|
||||
|
||||
var deletedDashboardsCount int64
|
||||
deletedDashboards, err := dr.dashboardStore.GetSoftDeletedExpiredDashboards(ctx, daysInTrash)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user