mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Add usage stats preview endpoint (#43899)
* Stats: add preview route for usage statistics * Stats: respect reporting settings * Stats: add tests to api endpoint * Stats: unregister route * Stats: always possible to preview stats * Update pkg/infra/usagestats/service/api.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:
parent
bedc5cccaa
commit
1e9818a69f
27
pkg/infra/usagestats/service/api.go
Normal file
27
pkg/infra/usagestats/service/api.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
const rootUrl = "/api/admin"
|
||||||
|
|
||||||
|
func (uss *UsageStats) registerAPIEndpoints() {
|
||||||
|
uss.RouteRegister.Group(rootUrl, func(subrouter routing.RouteRegister) {
|
||||||
|
subrouter.Get("/usage-report-preview", middleware.ReqGrafanaAdmin, routing.Wrap(uss.getUsageReportPreview))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uss *UsageStats) getUsageReportPreview(ctx *models.ReqContext) response.Response {
|
||||||
|
usageReport, err := uss.GetUsageReport(ctx.Req.Context())
|
||||||
|
if err != nil {
|
||||||
|
return response.Error(http.StatusInternalServerError, "failed to get usage report", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(http.StatusOK, usageReport)
|
||||||
|
}
|
134
pkg/infra/usagestats/service/api_test.go
Normal file
134
pkg/infra/usagestats/service/api_test.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/web"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApi_getUsageStats(t *testing.T) {
|
||||||
|
type getUsageStatsTestCase struct {
|
||||||
|
desc string
|
||||||
|
expectedStatus int
|
||||||
|
expectedCall bool
|
||||||
|
IsGrafanaAdmin bool
|
||||||
|
enabled bool
|
||||||
|
}
|
||||||
|
tests := []getUsageStatsTestCase{
|
||||||
|
{
|
||||||
|
desc: "expect usage stats",
|
||||||
|
enabled: true,
|
||||||
|
IsGrafanaAdmin: true,
|
||||||
|
expectedCall: true,
|
||||||
|
expectedStatus: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "expect usage stat preview still there after disabling",
|
||||||
|
enabled: false,
|
||||||
|
IsGrafanaAdmin: true,
|
||||||
|
expectedCall: true,
|
||||||
|
expectedStatus: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "expect http status 403 when not admin",
|
||||||
|
enabled: false,
|
||||||
|
IsGrafanaAdmin: false,
|
||||||
|
expectedCall: false,
|
||||||
|
expectedStatus: 403,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
uss := createService(t, setting.Cfg{})
|
||||||
|
uss.registerAPIEndpoints()
|
||||||
|
getSystemStatsWasCalled := false
|
||||||
|
|
||||||
|
uss.Bus.AddHandler(func(ctx context.Context, query *models.GetSystemStatsQuery) error {
|
||||||
|
query.Result = &models.SystemStats{}
|
||||||
|
getSystemStatsWasCalled = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
uss.Bus.AddHandler(func(ctx context.Context, query *models.GetDataSourceStatsQuery) error {
|
||||||
|
query.Result = []*models.DataSourceStats{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
uss.Bus.AddHandler(func(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error {
|
||||||
|
query.Result = []*models.DataSource{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
uss.Bus.AddHandler(func(ctx context.Context, query *models.GetDataSourceAccessStatsQuery) error {
|
||||||
|
query.Result = []*models.DataSourceAccessStats{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
uss.Bus.AddHandler(func(ctx context.Context, query *models.GetAlertNotifierUsageStatsQuery) error {
|
||||||
|
query.Result = []*models.NotifierUsageStats{}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.desc, func(t *testing.T) {
|
||||||
|
getSystemStatsWasCalled = false
|
||||||
|
uss.Cfg.ReportingEnabled = tt.enabled
|
||||||
|
server := setupTestServer(t, &models.SignedInUser{OrgId: 1, IsGrafanaAdmin: tt.IsGrafanaAdmin}, uss)
|
||||||
|
|
||||||
|
usageStats, recorder := getUsageStats(t, server)
|
||||||
|
require.Equal(t, tt.expectedCall, getSystemStatsWasCalled)
|
||||||
|
require.Equal(t, tt.expectedStatus, recorder.Code)
|
||||||
|
|
||||||
|
if tt.expectedStatus == http.StatusOK {
|
||||||
|
require.NotNil(t, usageStats)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUsageStats(t *testing.T, server *web.Mux) (*models.SystemStats, *httptest.ResponseRecorder) {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "/api/admin/usage-report-preview", http.NoBody)
|
||||||
|
require.NoError(t, err)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
server.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
var usageStats *models.SystemStats
|
||||||
|
if recorder.Code == http.StatusOK {
|
||||||
|
require.NoError(t, json.NewDecoder(recorder.Body).Decode(&usageStats))
|
||||||
|
}
|
||||||
|
return usageStats, recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTestServer(t *testing.T, user *models.SignedInUser, service *UsageStats) *web.Mux {
|
||||||
|
server := web.New()
|
||||||
|
server.UseMiddleware(web.Renderer(path.Join(setting.StaticRootPath, "views"), "[[", "]]"))
|
||||||
|
server.Use(contextProvider(&testContext{user}))
|
||||||
|
service.RouteRegister.Register(server)
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
type testContext struct {
|
||||||
|
user *models.SignedInUser
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextProvider(tc *testContext) web.Handler {
|
||||||
|
return func(c *web.Context) {
|
||||||
|
signedIn := tc.user != nil
|
||||||
|
reqCtx := &models.ReqContext{
|
||||||
|
Context: c,
|
||||||
|
SignedInUser: tc.user,
|
||||||
|
IsSignedIn: signedIn,
|
||||||
|
SkipCache: true,
|
||||||
|
Logger: log.New("test"),
|
||||||
|
}
|
||||||
|
c.Map(reqCtx)
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
@ -22,6 +23,7 @@ type UsageStats struct {
|
|||||||
pluginStore plugins.Store
|
pluginStore plugins.Store
|
||||||
SocialService social.Service
|
SocialService social.Service
|
||||||
kvStore *kvstore.NamespacedKVStore
|
kvStore *kvstore.NamespacedKVStore
|
||||||
|
RouteRegister routing.RouteRegister
|
||||||
|
|
||||||
log log.MultiLoggers
|
log log.MultiLoggers
|
||||||
|
|
||||||
@ -33,18 +35,22 @@ type UsageStats struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(cfg *setting.Cfg, bus bus.Bus, sqlStore *sqlstore.SQLStore, pluginStore plugins.Store,
|
func ProvideService(cfg *setting.Cfg, bus bus.Bus, sqlStore *sqlstore.SQLStore, pluginStore plugins.Store,
|
||||||
socialService social.Service, kvStore kvstore.KVStore) *UsageStats {
|
socialService social.Service, kvStore kvstore.KVStore, routeRegister routing.RouteRegister,
|
||||||
|
) *UsageStats {
|
||||||
s := &UsageStats{
|
s := &UsageStats{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Bus: bus,
|
Bus: bus,
|
||||||
SQLStore: sqlStore,
|
SQLStore: sqlStore,
|
||||||
oauthProviders: socialService.GetOAuthProviders(),
|
oauthProviders: socialService.GetOAuthProviders(),
|
||||||
|
RouteRegister: routeRegister,
|
||||||
pluginStore: pluginStore,
|
pluginStore: pluginStore,
|
||||||
kvStore: kvstore.WithNamespace(kvStore, 0, "infra.usagestats"),
|
kvStore: kvstore.WithNamespace(kvStore, 0, "infra.usagestats"),
|
||||||
log: log.New("infra.usagestats"),
|
log: log.New("infra.usagestats"),
|
||||||
startTime: time.Now(),
|
startTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.registerAPIEndpoints()
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/api/routing"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||||
@ -619,5 +620,6 @@ func createService(t *testing.T, cfg setting.Cfg) *UsageStats {
|
|||||||
kvStore: kvstore.WithNamespace(kvstore.ProvideService(sqlStore), 0, "infra.usagestats"),
|
kvStore: kvstore.WithNamespace(kvstore.ProvideService(sqlStore), 0, "infra.usagestats"),
|
||||||
log: log.New("infra.usagestats"),
|
log: log.New("infra.usagestats"),
|
||||||
startTime: time.Now().Add(-1 * time.Minute),
|
startTime: time.Now().Add(-1 * time.Minute),
|
||||||
|
RouteRegister: routing.NewRouteRegister(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user