mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PublicDashboards: refactor service (#57372)
This commit is contained in:
committed by
GitHub
parent
f161c5407a
commit
5b9959014c
@@ -6,21 +6,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/queries"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||
"github.com/grafana/grafana/pkg/services/query"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/grafanads"
|
||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||
)
|
||||
@@ -207,190 +203,6 @@ func (pd *PublicDashboardServiceImpl) updatePublicDashboardConfig(ctx context.Co
|
||||
return dto.PublicDashboard.Uid, pd.store.UpdatePublicDashboardConfig(ctx, cmd)
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) GetQueryDataResponse(ctx context.Context, skipCache bool, queryDto PublicDashboardQueryDTO, panelId int64, accessToken string) (*backend.QueryDataResponse, error) {
|
||||
publicDashboard, dashboard, err := pd.GetPublicDashboard(ctx, accessToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metricReq, err := pd.GetMetricRequest(ctx, dashboard, publicDashboard, panelId, queryDto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(metricReq.Queries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
anonymousUser := pd.BuildAnonymousUser(ctx, dashboard)
|
||||
res, err := pd.QueryDataService.QueryData(ctx, anonymousUser, skipCache, metricReq)
|
||||
|
||||
reqDatasources := metricReq.GetUniqueDatasourceTypes()
|
||||
if err != nil {
|
||||
LogQueryFailure(reqDatasources, pd.log, err)
|
||||
return nil, err
|
||||
}
|
||||
LogQuerySuccess(reqDatasources, pd.log)
|
||||
|
||||
queries.SanitizeMetadataFromQueryData(res)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) GetMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64, queryDto PublicDashboardQueryDTO) (dtos.MetricRequest, error) {
|
||||
err := validation.ValidateQueryPublicDashboardRequest(queryDto)
|
||||
if err != nil {
|
||||
return dtos.MetricRequest{}, err
|
||||
}
|
||||
|
||||
metricReqDTO, err := pd.buildMetricRequest(
|
||||
ctx,
|
||||
dashboard,
|
||||
publicDashboard,
|
||||
panelId,
|
||||
queryDto,
|
||||
)
|
||||
if err != nil {
|
||||
return dtos.MetricRequest{}, err
|
||||
}
|
||||
|
||||
return metricReqDTO, nil
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) GetAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error) {
|
||||
_, dash, err := pd.GetPublicDashboard(ctx, accessToken)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
annoDto, err := UnmarshalDashboardAnnotations(dash.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
anonymousUser := pd.BuildAnonymousUser(ctx, dash)
|
||||
|
||||
uniqueEvents := make(map[int64]AnnotationEvent, 0)
|
||||
for _, anno := range annoDto.Annotations.List {
|
||||
// skip annotations that are not enabled or are not a grafana datasource
|
||||
if !anno.Enable || (*anno.Datasource.Uid != grafanads.DatasourceUID && *anno.Datasource.Uid != grafanads.DatasourceName) {
|
||||
continue
|
||||
}
|
||||
annoQuery := &annotations.ItemQuery{
|
||||
From: reqDTO.From,
|
||||
To: reqDTO.To,
|
||||
OrgId: dash.OrgId,
|
||||
DashboardId: dash.Id,
|
||||
DashboardUid: dash.Uid,
|
||||
Limit: anno.Target.Limit,
|
||||
MatchAny: anno.Target.MatchAny,
|
||||
SignedInUser: anonymousUser,
|
||||
}
|
||||
|
||||
if anno.Target.Type == "tags" {
|
||||
annoQuery.DashboardId = 0
|
||||
annoQuery.Tags = anno.Target.Tags
|
||||
}
|
||||
|
||||
annotationItems, err := pd.AnnotationsRepo.Find(ctx, annoQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, item := range annotationItems {
|
||||
event := AnnotationEvent{
|
||||
Id: item.Id,
|
||||
DashboardId: item.DashboardId,
|
||||
Tags: item.Tags,
|
||||
IsRegion: item.TimeEnd > 0 && item.Time != item.TimeEnd,
|
||||
Text: item.Text,
|
||||
Color: *anno.IconColor,
|
||||
Time: item.Time,
|
||||
TimeEnd: item.TimeEnd,
|
||||
Source: anno,
|
||||
}
|
||||
|
||||
// We want dashboard annotations to reference the panel they're for. If no panelId is provided, they'll show up on all panels
|
||||
// which is only intended for tag and org annotations.
|
||||
if anno.Type == "dashboard" {
|
||||
event.PanelId = item.PanelId
|
||||
}
|
||||
|
||||
// We want events from tag queries to overwrite existing events
|
||||
_, has := uniqueEvents[event.Id]
|
||||
if !has || (has && anno.Target.Type == "tags") {
|
||||
uniqueEvents[event.Id] = event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var results []AnnotationEvent
|
||||
for _, result := range uniqueEvents {
|
||||
results = append(results, result)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// buildMetricRequest merges public dashboard parameters with
|
||||
// dashboard and returns a metrics request to be sent to query backend
|
||||
func (pd *PublicDashboardServiceImpl) buildMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64, reqDTO PublicDashboardQueryDTO) (dtos.MetricRequest, error) {
|
||||
// group queries by panel
|
||||
queriesByPanel := queries.GroupQueriesByPanelId(dashboard.Data)
|
||||
queries, ok := queriesByPanel[panelId]
|
||||
if !ok {
|
||||
return dtos.MetricRequest{}, ErrPublicDashboardPanelNotFound
|
||||
}
|
||||
|
||||
ts := publicDashboard.BuildTimeSettings(dashboard)
|
||||
|
||||
// determine safe resolution to query data at
|
||||
safeInterval, safeResolution := pd.getSafeIntervalAndMaxDataPoints(reqDTO, ts)
|
||||
for i := range queries {
|
||||
queries[i].Set("intervalMs", safeInterval)
|
||||
queries[i].Set("maxDataPoints", safeResolution)
|
||||
}
|
||||
|
||||
return dtos.MetricRequest{
|
||||
From: ts.From,
|
||||
To: ts.To,
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BuildAnonymousUser creates a user with permissions to read from all datasources used in the dashboard
|
||||
func (pd *PublicDashboardServiceImpl) BuildAnonymousUser(ctx context.Context, dashboard *models.Dashboard) *user.SignedInUser {
|
||||
datasourceUids := queries.GetUniqueDashboardDatasourceUids(dashboard.Data)
|
||||
|
||||
// Create a user with blank permissions
|
||||
anonymousUser := &user.SignedInUser{OrgID: dashboard.OrgId, Permissions: make(map[int64]map[string][]string)}
|
||||
|
||||
// Scopes needed for Annotation queries
|
||||
annotationScopes := []string{accesscontrol.ScopeAnnotationsTypeDashboard}
|
||||
// Need to access all dashboards since tags annotations span across all dashboards
|
||||
dashboardScopes := []string{dashboards.ScopeDashboardsProvider.GetResourceAllScope()}
|
||||
|
||||
// Scopes needed for datasource queries
|
||||
queryScopes := make([]string, 0)
|
||||
readScopes := make([]string, 0)
|
||||
for _, uid := range datasourceUids {
|
||||
scope := datasources.ScopeProvider.GetResourceScopeUID(uid)
|
||||
queryScopes = append(queryScopes, scope)
|
||||
readScopes = append(readScopes, scope)
|
||||
}
|
||||
|
||||
// Apply all scopes to the actions we need the user to be able to perform
|
||||
permissions := make(map[string][]string)
|
||||
permissions[datasources.ActionQuery] = queryScopes
|
||||
permissions[datasources.ActionRead] = readScopes
|
||||
permissions[accesscontrol.ActionAnnotationsRead] = annotationScopes
|
||||
permissions[dashboards.ActionDashboardsRead] = dashboardScopes
|
||||
|
||||
anonymousUser.Permissions[dashboard.OrgId] = permissions
|
||||
|
||||
return anonymousUser
|
||||
}
|
||||
|
||||
// Gets a list of public dashboards by orgId
|
||||
func (pd *PublicDashboardServiceImpl) ListPublicDashboards(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error) {
|
||||
publicDashboards, err := pd.store.ListPublicDashboards(ctx, orgId)
|
||||
@@ -402,11 +214,11 @@ func (pd *PublicDashboardServiceImpl) ListPublicDashboards(ctx context.Context,
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error) {
|
||||
return pd.store.PublicDashboardEnabled(ctx, dashboardUid)
|
||||
return pd.store.PublicDashboardEnabledExistsByDashboardUid(ctx, dashboardUid)
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) AccessTokenExists(ctx context.Context, accessToken string) (bool, error) {
|
||||
return pd.store.AccessTokenExists(ctx, accessToken)
|
||||
func (pd *PublicDashboardServiceImpl) PublicDashboardEnabledExistsByAccessToken(ctx context.Context, accessToken string) (bool, error) {
|
||||
return pd.store.PublicDashboardEnabledExistsByAccessToken(ctx, accessToken)
|
||||
}
|
||||
|
||||
func (pd *PublicDashboardServiceImpl) GetPublicDashboardOrgId(ctx context.Context, accessToken string) (int64, error) {
|
||||
|
||||
Reference in New Issue
Block a user