mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
This reverts commit 326ea86a57
.
This commit is contained in:
parent
228ec4c0f3
commit
96cdf77995
@ -245,7 +245,7 @@ func (hs *HTTPServer) AdminDeleteUser(c *models.ReqContext) response.Response {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
g.Go(func() error {
|
g.Go(func() error {
|
||||||
if err := hs.QuotaService.DeleteQuotaForUser(ctx, cmd.UserID); err != nil {
|
if err := hs.QuotaService.DeleteByUser(ctx, cmd.UserID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -36,16 +36,12 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/plugins"
|
"github.com/grafana/grafana/pkg/plugins"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
|
||||||
"github.com/grafana/grafana/pkg/services/correlations"
|
"github.com/grafana/grafana/pkg/services/correlations"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
publicdashboardsapi "github.com/grafana/grafana/pkg/services/publicdashboards/api"
|
publicdashboardsapi "github.com/grafana/grafana/pkg/services/publicdashboards/api"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
@ -73,8 +69,8 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
|
|
||||||
// not logged in views
|
// not logged in views
|
||||||
r.Get("/logout", hs.Logout)
|
r.Get("/logout", hs.Logout)
|
||||||
r.Post("/login", quota(string(auth.QuotaTargetSrv)), routing.Wrap(hs.LoginPost))
|
r.Post("/login", quota("session"), routing.Wrap(hs.LoginPost))
|
||||||
r.Get("/login/:name", quota(string(auth.QuotaTargetSrv)), hs.OAuthLogin)
|
r.Get("/login/:name", quota("session"), hs.OAuthLogin)
|
||||||
r.Get("/login", hs.LoginView)
|
r.Get("/login", hs.LoginView)
|
||||||
r.Get("/invite/:code", hs.Index)
|
r.Get("/invite/:code", hs.Index)
|
||||||
|
|
||||||
@ -177,7 +173,7 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
r.Get("/verify", hs.Index)
|
r.Get("/verify", hs.Index)
|
||||||
r.Get("/signup", hs.Index)
|
r.Get("/signup", hs.Index)
|
||||||
r.Get("/api/user/signup/options", routing.Wrap(GetSignUpOptions))
|
r.Get("/api/user/signup/options", routing.Wrap(GetSignUpOptions))
|
||||||
r.Post("/api/user/signup", quota(user.QuotaTargetSrv), quota(org.QuotaTargetSrv), routing.Wrap(hs.SignUp))
|
r.Post("/api/user/signup", quota("user"), routing.Wrap(hs.SignUp))
|
||||||
r.Post("/api/user/signup/step2", routing.Wrap(hs.SignUpStep2))
|
r.Post("/api/user/signup/step2", routing.Wrap(hs.SignUpStep2))
|
||||||
|
|
||||||
// invited
|
// invited
|
||||||
@ -196,7 +192,7 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
r.Get("/dashboard/snapshots/", reqSignedIn, hs.Index)
|
r.Get("/dashboard/snapshots/", reqSignedIn, hs.Index)
|
||||||
|
|
||||||
// api renew session based on cookie
|
// api renew session based on cookie
|
||||||
r.Get("/api/login/ping", quota(string(auth.QuotaTargetSrv)), routing.Wrap(hs.LoginAPIPing))
|
r.Get("/api/login/ping", quota("session"), routing.Wrap(hs.LoginAPIPing))
|
||||||
|
|
||||||
// expose plugin file system assets
|
// expose plugin file system assets
|
||||||
r.Get("/public/plugins/:pluginId/*", hs.getPluginAssets)
|
r.Get("/public/plugins/:pluginId/*", hs.getPluginAssets)
|
||||||
@ -302,13 +298,13 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
orgRoute.Put("/address", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgsWrite)), routing.Wrap(hs.UpdateCurrentOrgAddress))
|
orgRoute.Put("/address", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgsWrite)), routing.Wrap(hs.UpdateCurrentOrgAddress))
|
||||||
orgRoute.Get("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.GetOrgUsersForCurrentOrg))
|
orgRoute.Get("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.GetOrgUsersForCurrentOrg))
|
||||||
orgRoute.Get("/users/search", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.SearchOrgUsersWithPaging))
|
orgRoute.Get("/users/search", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRead)), routing.Wrap(hs.SearchOrgUsersWithPaging))
|
||||||
orgRoute.Post("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), quota(user.QuotaTargetSrv), quota(org.QuotaTargetSrv), routing.Wrap(hs.AddOrgUserToCurrentOrg))
|
orgRoute.Post("/users", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd, ac.ScopeUsersAll)), quota("user"), routing.Wrap(hs.AddOrgUserToCurrentOrg))
|
||||||
orgRoute.Patch("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersWrite, userIDScope)), routing.Wrap(hs.UpdateOrgUserForCurrentOrg))
|
orgRoute.Patch("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersWrite, userIDScope)), routing.Wrap(hs.UpdateOrgUserForCurrentOrg))
|
||||||
orgRoute.Delete("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUserForCurrentOrg))
|
orgRoute.Delete("/users/:userId", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersRemove, userIDScope)), routing.Wrap(hs.RemoveOrgUserForCurrentOrg))
|
||||||
|
|
||||||
// invites
|
// invites
|
||||||
orgRoute.Get("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd)), routing.Wrap(hs.GetPendingOrgInvites))
|
orgRoute.Get("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd)), routing.Wrap(hs.GetPendingOrgInvites))
|
||||||
orgRoute.Post("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd)), quota(user.QuotaTargetSrv), quota(user.QuotaTargetSrv), routing.Wrap(hs.AddOrgInvite))
|
orgRoute.Post("/invites", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd)), quota("user"), routing.Wrap(hs.AddOrgInvite))
|
||||||
orgRoute.Patch("/invites/:code/revoke", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd)), routing.Wrap(hs.RevokeInvite))
|
orgRoute.Patch("/invites/:code/revoke", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionOrgUsersAdd)), routing.Wrap(hs.RevokeInvite))
|
||||||
|
|
||||||
// prefs
|
// prefs
|
||||||
@ -335,7 +331,7 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// create new org
|
// create new org
|
||||||
apiRoute.Post("/orgs", authorizeInOrg(reqSignedIn, ac.UseGlobalOrg, ac.EvalPermission(ac.ActionOrgsCreate)), quota(org.QuotaTargetSrv), routing.Wrap(hs.CreateOrg))
|
apiRoute.Post("/orgs", authorizeInOrg(reqSignedIn, ac.UseGlobalOrg, ac.EvalPermission(ac.ActionOrgsCreate)), quota("org"), routing.Wrap(hs.CreateOrg))
|
||||||
|
|
||||||
// search all orgs
|
// search all orgs
|
||||||
apiRoute.Get("/orgs", authorizeInOrg(reqGrafanaAdmin, ac.UseGlobalOrg, ac.EvalPermission(ac.ActionOrgsRead)), routing.Wrap(hs.SearchOrgs))
|
apiRoute.Get("/orgs", authorizeInOrg(reqGrafanaAdmin, ac.UseGlobalOrg, ac.EvalPermission(ac.ActionOrgsRead)), routing.Wrap(hs.SearchOrgs))
|
||||||
@ -362,7 +358,7 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) {
|
apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) {
|
||||||
apikeyIDScope := ac.Scope("apikeys", "id", ac.Parameter(":id"))
|
apikeyIDScope := ac.Scope("apikeys", "id", ac.Parameter(":id"))
|
||||||
keysRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyRead)), routing.Wrap(hs.GetAPIKeys))
|
keysRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyRead)), routing.Wrap(hs.GetAPIKeys))
|
||||||
keysRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyCreate)), quota(string(apikey.QuotaTargetSrv)), routing.Wrap(hs.AddAPIKey))
|
keysRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyCreate)), quota("api_key"), routing.Wrap(hs.AddAPIKey))
|
||||||
keysRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyDelete, apikeyIDScope)), routing.Wrap(hs.DeleteAPIKey))
|
keysRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(ac.ActionAPIKeyDelete, apikeyIDScope)), routing.Wrap(hs.DeleteAPIKey))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -377,7 +373,7 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
uidScope := datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":uid"))
|
uidScope := datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":uid"))
|
||||||
nameScope := datasources.ScopeProvider.GetResourceScopeName(ac.Parameter(":name"))
|
nameScope := datasources.ScopeProvider.GetResourceScopeName(ac.Parameter(":name"))
|
||||||
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(hs.GetDataSources))
|
datasourceRoute.Get("/", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(hs.GetDataSources))
|
||||||
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionCreate)), quota(string(datasources.QuotaTargetSrv)), routing.Wrap(hs.AddDataSource))
|
datasourceRoute.Post("/", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionCreate)), quota("data_source"), routing.Wrap(hs.AddDataSource))
|
||||||
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, idScope)), routing.Wrap(hs.UpdateDataSourceByID))
|
datasourceRoute.Put("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, idScope)), routing.Wrap(hs.UpdateDataSourceByID))
|
||||||
datasourceRoute.Put("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(hs.UpdateDataSourceByUID))
|
datasourceRoute.Put("/uid/:uid", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(hs.UpdateDataSourceByUID))
|
||||||
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDelete, idScope)), routing.Wrap(hs.DeleteDataSourceById))
|
datasourceRoute.Delete("/:id", authorize(reqOrgAdmin, ac.EvalPermission(datasources.ActionDelete, idScope)), routing.Wrap(hs.DeleteDataSourceById))
|
||||||
|
@ -45,6 +45,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||||
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
||||||
|
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
"github.com/grafana/grafana/pkg/services/rendering"
|
"github.com/grafana/grafana/pkg/services/rendering"
|
||||||
"github.com/grafana/grafana/pkg/services/search"
|
"github.com/grafana/grafana/pkg/services/search"
|
||||||
@ -248,13 +249,15 @@ func (s *fakeRenderService) Init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setupAccessControlScenarioContext(t *testing.T, cfg *setting.Cfg, url string, permissions []accesscontrol.Permission) (*scenarioContext, *HTTPServer) {
|
func setupAccessControlScenarioContext(t *testing.T, cfg *setting.Cfg, url string, permissions []accesscontrol.Permission) (*scenarioContext, *HTTPServer) {
|
||||||
store := sqlstore.InitTestDB(t)
|
cfg.Quota.Enabled = false
|
||||||
|
|
||||||
|
store := db.InitTestDB(t)
|
||||||
hs := &HTTPServer{
|
hs := &HTTPServer{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Live: newTestLive(t, store),
|
Live: newTestLive(t, store),
|
||||||
License: &licensing.OSSLicensingService{},
|
License: &licensing.OSSLicensingService{},
|
||||||
Features: featuremgmt.WithFeatures(),
|
Features: featuremgmt.WithFeatures(),
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{Cfg: cfg},
|
||||||
RouteRegister: routing.NewRouteRegister(),
|
RouteRegister: routing.NewRouteRegister(),
|
||||||
AccessControl: accesscontrolmock.New().WithPermissions(permissions),
|
AccessControl: accesscontrolmock.New().WithPermissions(permissions),
|
||||||
searchUsersService: searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), usertest.NewUserServiceFake()),
|
searchUsersService: searchusers.ProvideUsersService(filters.ProvideOSSSearchUserFilter(), usertest.NewUserServiceFake()),
|
||||||
@ -373,9 +376,7 @@ func setupHTTPServerWithCfgDb(
|
|||||||
routeRegister := routing.NewRouteRegister()
|
routeRegister := routing.NewRouteRegister()
|
||||||
teamService := teamimpl.ProvideService(db, cfg)
|
teamService := teamimpl.ProvideService(db, cfg)
|
||||||
cfg.IsFeatureToggleEnabled = features.IsEnabled
|
cfg.IsFeatureToggleEnabled = features.IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardsStore := dashboardsstore.ProvideDashboardStore(db, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db, cfg))
|
||||||
dashboardsStore, err := dashboardsstore.ProvideDashboardStore(db, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
var acmock *accesscontrolmock.Mock
|
var acmock *accesscontrolmock.Mock
|
||||||
var ac accesscontrol.AccessControl
|
var ac accesscontrol.AccessControl
|
||||||
@ -401,8 +402,7 @@ func setupHTTPServerWithCfgDb(
|
|||||||
acService, err = acimpl.ProvideService(cfg, db, routeRegister, localcache.ProvideService(), featuremgmt.WithFeatures())
|
acService, err = acimpl.ProvideService(cfg, db, routeRegister, localcache.ProvideService(), featuremgmt.WithFeatures())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ac = acimpl.ProvideAccessControl(cfg)
|
ac = acimpl.ProvideAccessControl(cfg)
|
||||||
userSvc, err = userimpl.ProvideService(db, nil, cfg, teamimpl.ProvideService(db, cfg), localcache.ProvideService(), quotatest.New(false, nil))
|
userSvc = userimpl.ProvideService(db, nil, cfg, teamimpl.ProvideService(db, cfg), localcache.ProvideService())
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, license, acService, teamService, userSvc)
|
teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, license, acService, teamService, userSvc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -412,7 +412,7 @@ func setupHTTPServerWithCfgDb(
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Features: features,
|
Features: features,
|
||||||
Live: newTestLive(t, db),
|
Live: newTestLive(t, db),
|
||||||
QuotaService: quotaService,
|
QuotaService: "aimpl.Service{Cfg: cfg},
|
||||||
RouteRegister: routeRegister,
|
RouteRegister: routeRegister,
|
||||||
SQLStore: store,
|
SQLStore: store,
|
||||||
License: &licensing.OSSLicensingService{},
|
License: &licensing.OSSLicensingService{},
|
||||||
@ -497,7 +497,7 @@ func SetupAPITestServer(t *testing.T, opts ...APITestServerOption) *webtest.Serv
|
|||||||
RouteRegister: routing.NewRouteRegister(),
|
RouteRegister: routing.NewRouteRegister(),
|
||||||
License: &licensing.OSSLicensingService{},
|
License: &licensing.OSSLicensingService{},
|
||||||
Features: featuremgmt.WithFeatures(),
|
Features: featuremgmt.WithFeatures(),
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: quotatest.NewQuotaServiceFake(),
|
||||||
searchUsersService: &searchusers.OSSService{},
|
searchUsersService: &searchusers.OSSService{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +407,7 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
|
|||||||
dash := cmd.GetDashboardModel()
|
dash := cmd.GetDashboardModel()
|
||||||
newDashboard := dash.Id == 0
|
newDashboard := dash.Id == 0
|
||||||
if newDashboard {
|
if newDashboard {
|
||||||
limitReached, err := hs.QuotaService.QuotaReached(c, dashboards.QuotaTargetSrv)
|
limitReached, err := hs.QuotaService.QuotaReached(c, "dashboard")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Error(500, "failed to get quota", err)
|
return response.Error(500, "failed to get quota", err)
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ import (
|
|||||||
pref "github.com/grafana/grafana/pkg/services/preference"
|
pref "github.com/grafana/grafana/pkg/services/preference"
|
||||||
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
"github.com/grafana/grafana/pkg/services/preference/preftest"
|
||||||
"github.com/grafana/grafana/pkg/services/provisioning"
|
"github.com/grafana/grafana/pkg/services/provisioning"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
@ -150,7 +150,6 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
|||||||
DashboardService: dashboardService,
|
DashboardService: dashboardService,
|
||||||
dashboardVersionService: fakeDashboardVersionService,
|
dashboardVersionService: fakeDashboardVersionService,
|
||||||
Coremodels: registry.NewBase(nil),
|
Coremodels: registry.NewBase(nil),
|
||||||
QuotaService: quotatest.New(false, nil),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setUp := func() {
|
setUp := func() {
|
||||||
@ -991,12 +990,9 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
|||||||
provisioningService = provisioning.NewProvisioningServiceMock(context.Background())
|
provisioningService = provisioning.NewProvisioningServiceMock(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
|
||||||
if dashboardStore == nil {
|
if dashboardStore == nil {
|
||||||
sql := db.InitTestDB(t)
|
sql := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = database.ProvideDashboardStore(sql, sql.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql, sql.Cfg))
|
||||||
dashboardStore, err = database.ProvideDashboardStore(sql, sql.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql, sql.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryPanelsService := mockLibraryPanelService{}
|
libraryPanelsService := mockLibraryPanelService{}
|
||||||
@ -1035,7 +1031,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
|||||||
require.Equal(sc.t, 200, sc.resp.Code)
|
require.Equal(sc.t, 200, sc.resp.Code)
|
||||||
|
|
||||||
dash := dtos.DashboardFullWithMeta{}
|
dash := dtos.DashboardFullWithMeta{}
|
||||||
err = json.NewDecoder(sc.resp.Body).Decode(&dash)
|
err := json.NewDecoder(sc.resp.Body).Decode(&dash)
|
||||||
require.NoError(sc.t, err)
|
require.NoError(sc.t, err)
|
||||||
|
|
||||||
return dash
|
return dash
|
||||||
@ -1084,7 +1080,9 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||||
Live: newTestLive(t, db.InitTestDB(t)),
|
Live: newTestLive(t, db.InitTestDB(t)),
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{
|
||||||
|
Cfg: cfg,
|
||||||
|
},
|
||||||
pluginStore: &plugins.FakePluginStore{},
|
pluginStore: &plugins.FakePluginStore{},
|
||||||
LibraryPanelService: &mockLibraryPanelService{},
|
LibraryPanelService: &mockLibraryPanelService{},
|
||||||
LibraryElementService: &mockLibraryElementService{},
|
LibraryElementService: &mockLibraryElementService{},
|
||||||
@ -1118,7 +1116,7 @@ func postValidateScenario(t *testing.T, desc string, url string, routePattern st
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||||
Live: newTestLive(t, db.InitTestDB(t)),
|
Live: newTestLive(t, db.InitTestDB(t)),
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{Cfg: cfg},
|
||||||
LibraryPanelService: &mockLibraryPanelService{},
|
LibraryPanelService: &mockLibraryPanelService{},
|
||||||
LibraryElementService: &mockLibraryElementService{},
|
LibraryElementService: &mockLibraryElementService{},
|
||||||
SQLStore: sqlmock,
|
SQLStore: sqlmock,
|
||||||
@ -1154,7 +1152,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||||
Live: newTestLive(t, db.InitTestDB(t)),
|
Live: newTestLive(t, db.InitTestDB(t)),
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{Cfg: cfg},
|
||||||
LibraryPanelService: &mockLibraryPanelService{},
|
LibraryPanelService: &mockLibraryPanelService{},
|
||||||
LibraryElementService: &mockLibraryElementService{},
|
LibraryElementService: &mockLibraryElementService{},
|
||||||
SQLStore: sqlmock,
|
SQLStore: sqlmock,
|
||||||
@ -1192,7 +1190,7 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
|
|||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()),
|
||||||
Live: newTestLive(t, db.InitTestDB(t)),
|
Live: newTestLive(t, db.InitTestDB(t)),
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{Cfg: cfg},
|
||||||
LibraryPanelService: &mockLibraryPanelService{},
|
LibraryPanelService: &mockLibraryPanelService{},
|
||||||
LibraryElementService: &mockLibraryElementService{},
|
LibraryElementService: &mockLibraryElementService{},
|
||||||
DashboardService: mock,
|
DashboardService: mock,
|
||||||
|
@ -146,7 +146,7 @@ func TestHTTPServer_FolderMetadata(t *testing.T) {
|
|||||||
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
server := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
hs.folderService = folderService
|
hs.folderService = folderService
|
||||||
hs.AccessControl = acmock.New()
|
hs.AccessControl = acmock.New()
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should attach access control metadata to multiple folders", func(t *testing.T) {
|
t.Run("Should attach access control metadata to multiple folders", func(t *testing.T) {
|
||||||
|
@ -94,12 +94,12 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) {
|
|||||||
serverFeatureEnabled := SetupAPITestServer(t, func(hs *HTTPServer) {
|
serverFeatureEnabled := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
hs.queryDataService = qds
|
hs.queryDataService = qds
|
||||||
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagDatasourceQueryMultiStatus, true)
|
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagDatasourceQueryMultiStatus, true)
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
serverFeatureDisabled := SetupAPITestServer(t, func(hs *HTTPServer) {
|
serverFeatureDisabled := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
hs.queryDataService = qds
|
hs.queryDataService = qds
|
||||||
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagDatasourceQueryMultiStatus, false)
|
hs.Features = featuremgmt.WithFeatures(featuremgmt.FlagDatasourceQueryMultiStatus, false)
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Status code is 400 when data source response has an error and feature toggle is disabled", func(t *testing.T) {
|
t.Run("Status code is 400 when data source response has an error and feature toggle is disabled", func(t *testing.T) {
|
||||||
@ -142,7 +142,7 @@ func TestAPIEndpoint_Metrics_PluginDecryptionFailure(t *testing.T) {
|
|||||||
)
|
)
|
||||||
httpServer := SetupAPITestServer(t, func(hs *HTTPServer) {
|
httpServer := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
hs.queryDataService = qds
|
hs.queryDataService = qds
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Status code is 500 and a secrets plugin error is returned if there is a problem getting secrets from the remote plugin", func(t *testing.T) {
|
t.Run("Status code is 500 and a secrets plugin error is returned if there is a problem getting secrets from the remote plugin", func(t *testing.T) {
|
||||||
@ -294,7 +294,7 @@ func TestDataSourceQueryError(t *testing.T) {
|
|||||||
pluginClient.ProvideService(r, &config.Cfg{}),
|
pluginClient.ProvideService(r, &config.Cfg{}),
|
||||||
&fakeOAuthTokenService{},
|
&fakeOAuthTokenService{},
|
||||||
)
|
)
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
req := srv.NewPostRequest("/api/ds/query", strings.NewReader(tc.request))
|
req := srv.NewPostRequest("/api/ds/query", strings.NewReader(tc.request))
|
||||||
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: org.RoleViewer})
|
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, OrgRole: org.RoleViewer})
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -105,8 +104,7 @@ func TestAPIEndpoint_PutCurrentOrg_LegacyAccessControl(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
setInitCtxSignedInOrgAdmin(sc.initCtx)
|
setInitCtxSignedInOrgAdmin(sc.initCtx)
|
||||||
sc.hs.orgService, err = orgimpl.ProvideService(sc.db, sc.cfg, quotatest.New(false, nil))
|
sc.hs.orgService = orgimpl.ProvideService(sc.db, sc.cfg)
|
||||||
require.NoError(t, err)
|
|
||||||
t.Run("Admin can update current org", func(t *testing.T) {
|
t.Run("Admin can update current org", func(t *testing.T) {
|
||||||
response := callAPI(sc.server, http.MethodPut, putCurrentOrgURL, input, t)
|
response := callAPI(sc.server, http.MethodPut, putCurrentOrgURL, input, t)
|
||||||
assert.Equal(t, http.StatusOK, response.Code)
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
@ -120,8 +118,7 @@ func TestAPIEndpoint_PutCurrentOrg_AccessControl(t *testing.T) {
|
|||||||
_, err := sc.db.CreateOrgWithMember("TestOrg", sc.initCtx.UserID)
|
_, err := sc.db.CreateOrgWithMember("TestOrg", sc.initCtx.UserID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sc.hs.orgService, err = orgimpl.ProvideService(sc.db, sc.cfg, quotatest.New(false, nil))
|
sc.hs.orgService = orgimpl.ProvideService(sc.db, sc.cfg)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
input := strings.NewReader(testUpdateOrgNameForm)
|
input := strings.NewReader(testUpdateOrgNameForm)
|
||||||
t.Run("AccessControl allows updating current org with correct permissions", func(t *testing.T) {
|
t.Run("AccessControl allows updating current org with correct permissions", func(t *testing.T) {
|
||||||
@ -439,9 +436,7 @@ func TestAPIEndpoint_PutOrg_LegacyAccessControl(t *testing.T) {
|
|||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
||||||
setInitCtxSignedInViewer(sc.initCtx)
|
setInitCtxSignedInViewer(sc.initCtx)
|
||||||
var err error
|
sc.hs.orgService = orgimpl.ProvideService(sc.db, sc.cfg)
|
||||||
sc.hs.orgService, err = orgimpl.ProvideService(sc.db, sc.cfg, quotatest.New(false, nil))
|
|
||||||
require.NoError(t, err)
|
|
||||||
// Create two orgs, to update another one than the logged in one
|
// Create two orgs, to update another one than the logged in one
|
||||||
setupOrgsDBForAccessControlTests(t, sc.db, sc, 2)
|
setupOrgsDBForAccessControlTests(t, sc.db, sc, 2)
|
||||||
|
|
||||||
@ -461,9 +456,7 @@ func TestAPIEndpoint_PutOrg_LegacyAccessControl(t *testing.T) {
|
|||||||
|
|
||||||
func TestAPIEndpoint_PutOrg_AccessControl(t *testing.T) {
|
func TestAPIEndpoint_PutOrg_AccessControl(t *testing.T) {
|
||||||
sc := setupHTTPServer(t, true)
|
sc := setupHTTPServer(t, true)
|
||||||
var err error
|
sc.hs.orgService = orgimpl.ProvideService(sc.db, sc.cfg)
|
||||||
sc.hs.orgService, err = orgimpl.ProvideService(sc.db, sc.cfg, quotatest.New(false, nil))
|
|
||||||
require.NoError(t, err)
|
|
||||||
// Create two orgs, to update another one than the logged in one
|
// Create two orgs, to update another one than the logged in one
|
||||||
setupOrgsDBForAccessControlTests(t, sc.db, sc, 2)
|
setupOrgsDBForAccessControlTests(t, sc.db, sc, 2)
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
||||||
@ -390,13 +389,11 @@ func TestGetOrgUsersAPIEndpoint_AccessControlMetadata(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = tc.enableAccessControl
|
cfg.RBACEnabled = tc.enableAccessControl
|
||||||
var err error
|
|
||||||
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
||||||
hs.userService, err = userimpl.ProvideService(
|
hs.userService = userimpl.ProvideService(
|
||||||
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(), quotatest.New(false, nil))
|
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(),
|
||||||
require.NoError(t, err)
|
)
|
||||||
hs.orgService, err = orgimpl.ProvideService(hs.SQLStore, cfg, quotatest.New(false, nil))
|
hs.orgService = orgimpl.ProvideService(hs.SQLStore, cfg)
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
})
|
||||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||||
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
||||||
@ -406,7 +403,7 @@ func TestGetOrgUsersAPIEndpoint_AccessControlMetadata(t *testing.T) {
|
|||||||
require.Equal(t, tc.expectedCode, response.Code)
|
require.Equal(t, tc.expectedCode, response.Code)
|
||||||
|
|
||||||
var userList []*models.OrgUserDTO
|
var userList []*models.OrgUserDTO
|
||||||
err = json.NewDecoder(response.Body).Decode(&userList)
|
err := json.NewDecoder(response.Body).Decode(&userList)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if tc.expectedMetadata != nil {
|
if tc.expectedMetadata != nil {
|
||||||
@ -496,14 +493,11 @@ func TestGetOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = tc.enableAccessControl
|
cfg.RBACEnabled = tc.enableAccessControl
|
||||||
var err error
|
|
||||||
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
||||||
quotaService := quotatest.New(false, nil)
|
hs.userService = userimpl.ProvideService(
|
||||||
hs.userService, err = userimpl.ProvideService(
|
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(),
|
||||||
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(), quotaService)
|
)
|
||||||
require.NoError(t, err)
|
hs.orgService = orgimpl.ProvideService(hs.SQLStore, cfg)
|
||||||
hs.orgService, err = orgimpl.ProvideService(hs.SQLStore, cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
})
|
||||||
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
||||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||||
@ -604,11 +598,10 @@ func TestPostOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = tc.enableAccessControl
|
cfg.RBACEnabled = tc.enableAccessControl
|
||||||
var err error
|
|
||||||
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
||||||
hs.userService, err = userimpl.ProvideService(
|
hs.userService = userimpl.ProvideService(
|
||||||
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(), quotatest.New(false, nil))
|
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(),
|
||||||
require.NoError(t, err)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||||
@ -723,12 +716,11 @@ func TestOrgUsersAPIEndpointWithSetPerms_AccessControl(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
var err error
|
|
||||||
sc := setupHTTPServer(t, true, func(hs *HTTPServer) {
|
sc := setupHTTPServer(t, true, func(hs *HTTPServer) {
|
||||||
hs.tempUserService = tempuserimpl.ProvideService(hs.SQLStore)
|
hs.tempUserService = tempuserimpl.ProvideService(hs.SQLStore)
|
||||||
hs.userService, err = userimpl.ProvideService(
|
hs.userService = userimpl.ProvideService(
|
||||||
hs.SQLStore, nil, setting.NewCfg(), teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), setting.NewCfg()), localcache.ProvideService(), quotatest.New(false, nil))
|
hs.SQLStore, nil, setting.NewCfg(), teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), setting.NewCfg()), localcache.ProvideService(),
|
||||||
require.NoError(t, err)
|
)
|
||||||
})
|
})
|
||||||
setInitCtxSignedInViewer(sc.initCtx)
|
setInitCtxSignedInViewer(sc.initCtx)
|
||||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||||
@ -843,14 +835,11 @@ func TestPatchOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = tc.enableAccessControl
|
cfg.RBACEnabled = tc.enableAccessControl
|
||||||
var err error
|
|
||||||
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
||||||
quotaService := quotatest.New(false, nil)
|
hs.userService = userimpl.ProvideService(
|
||||||
hs.userService, err = userimpl.ProvideService(
|
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(),
|
||||||
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(), quotaService)
|
)
|
||||||
require.NoError(t, err)
|
hs.orgService = orgimpl.ProvideService(hs.SQLStore, cfg)
|
||||||
hs.orgService, err = orgimpl.ProvideService(hs.SQLStore, cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
})
|
||||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||||
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
||||||
@ -973,14 +962,11 @@ func TestDeleteOrgUsersAPIEndpoint_AccessControl(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = tc.enableAccessControl
|
cfg.RBACEnabled = tc.enableAccessControl
|
||||||
var err error
|
|
||||||
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
sc := setupHTTPServerWithCfg(t, false, cfg, func(hs *HTTPServer) {
|
||||||
quotaService := quotatest.New(false, nil)
|
hs.userService = userimpl.ProvideService(
|
||||||
hs.userService, err = userimpl.ProvideService(
|
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(),
|
||||||
hs.SQLStore, nil, cfg, teamimpl.ProvideService(hs.SQLStore.(*sqlstore.SQLStore), cfg), localcache.ProvideService(), quotaService)
|
)
|
||||||
require.NoError(t, err)
|
hs.orgService = orgimpl.ProvideService(hs.SQLStore, cfg)
|
||||||
hs.orgService, err = orgimpl.ProvideService(hs.SQLStore, cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
})
|
||||||
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
setupOrgUsersDBForAccessControlTests(t, sc.db)
|
||||||
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
setInitCtxSignedInUser(sc.initCtx, tc.user)
|
||||||
|
@ -41,7 +41,7 @@ func TestGetPluginDashboards(t *testing.T) {
|
|||||||
|
|
||||||
s := SetupAPITestServer(t, func(hs *HTTPServer) {
|
s := SetupAPITestServer(t, func(hs *HTTPServer) {
|
||||||
hs.pluginDashboardService = pluginDashboardService
|
hs.pluginDashboardService = pluginDashboardService
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Not signed in should return 404 Not Found", func(t *testing.T) {
|
t.Run("Not signed in should return 404 Not Found", func(t *testing.T) {
|
||||||
|
@ -32,7 +32,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/oauthtoken"
|
"github.com/grafana/grafana/pkg/services/oauthtoken"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets"
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
@ -139,9 +138,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("When matching route path", func(t *testing.T) {
|
t.Run("When matching route path", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider,
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider,
|
||||||
&oauthtoken.Service{}, dsService, tracer)
|
&oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -154,9 +151,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("When matching route path and has dynamic url", func(t *testing.T) {
|
t.Run("When matching route path and has dynamic url", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/common/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[3]
|
proxy.matchedRoute = routes[3]
|
||||||
@ -168,9 +163,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("When matching route path with no url", func(t *testing.T) {
|
t.Run("When matching route path with no url", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[4]
|
proxy.matchedRoute = routes[4]
|
||||||
@ -181,9 +174,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("When matching route path and has dynamic body", func(t *testing.T) {
|
t.Run("When matching route path and has dynamic body", func(t *testing.T) {
|
||||||
ctx, req := setUp()
|
ctx, req := setUp()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/body", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
proxy.matchedRoute = routes[5]
|
proxy.matchedRoute = routes[5]
|
||||||
@ -197,9 +188,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("Validating request", func(t *testing.T) {
|
t.Run("Validating request", func(t *testing.T) {
|
||||||
t.Run("plugin route with valid role", func(t *testing.T) {
|
t.Run("plugin route with valid role", func(t *testing.T) {
|
||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/v4/some/method", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = proxy.validateRequest()
|
err = proxy.validateRequest()
|
||||||
@ -208,9 +197,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("plugin route with admin role and user is editor", func(t *testing.T) {
|
t.Run("plugin route with admin role and user is editor", func(t *testing.T) {
|
||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = proxy.validateRequest()
|
err = proxy.validateRequest()
|
||||||
@ -220,9 +207,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
t.Run("plugin route with admin role and user is admin", func(t *testing.T) {
|
t.Run("plugin route with admin role and user is admin", func(t *testing.T) {
|
||||||
ctx, _ := setUp()
|
ctx, _ := setUp()
|
||||||
ctx.SignedInUser.OrgRole = org.RoleAdmin
|
ctx.SignedInUser.OrgRole = org.RoleAdmin
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "api/admin", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = proxy.validateRequest()
|
err = proxy.validateRequest()
|
||||||
@ -313,9 +298,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
||||||
@ -331,9 +314,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
req, err := http.NewRequest("GET", "http://localhost/asd", nil)
|
req, err := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
client = newFakeHTTPClient(t, json2)
|
client = newFakeHTTPClient(t, json2)
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken2", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[1], dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[1], dsInfo, cfg)
|
||||||
@ -350,9 +331,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client = newFakeHTTPClient(t, []byte{})
|
client = newFakeHTTPClient(t, []byte{})
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "pathwithtoken1", cfg, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
ApplyRoute(proxy.ctx.Req.Context(), req, proxy.proxyPath, routes[0], dsInfo, cfg)
|
||||||
@ -376,9 +355,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{BuildVersion: "5.3.0"}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
@ -405,9 +382,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -433,9 +408,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -465,9 +438,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, pluginRoutes, ctx, "", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -492,9 +463,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
@ -545,9 +514,7 @@ func TestDataSourceProxy_routeRule(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/to/folder/", &setting.Cfg{}, httpClientProvider, &mockAuthToken, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err = http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err = http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
@ -684,9 +651,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -706,9 +671,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -724,9 +687,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -750,9 +711,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/render", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -779,9 +738,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -807,9 +764,7 @@ func TestDataSourceProxy_requestHandling(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "/path/%2Ftest%2Ftest%2F", &setting.Cfg{}, httpClientProvider, &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -835,11 +790,8 @@ func TestNewDataSourceProxy_InvalidURL(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
var err error
|
_, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
_, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.True(t, strings.HasPrefix(err.Error(), `validation of data source URL "://host/root" failed`))
|
assert.True(t, strings.HasPrefix(err.Error(), `validation of data source URL "://host/root" failed`))
|
||||||
}
|
}
|
||||||
@ -860,10 +812,8 @@ func TestNewDataSourceProxy_ProtocolLessURL(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
_, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
|
||||||
_, err = NewDataSourceProxy(&ds, routes, &ctx, "api/method", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
@ -906,9 +856,7 @@ func TestNewDataSourceProxy_MSSQL(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
p, err := NewDataSourceProxy(&ds, routes, &ctx, "api/method", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
if tc.err == nil {
|
if tc.err == nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -936,9 +884,7 @@ func getDatasourceProxiedRequest(t *testing.T, ctx *models.ReqContext, cfg *sett
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(ds, routes, ctx, "", cfg, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||||
@ -1055,9 +1001,7 @@ func runDatasourceAuthTest(t *testing.T, secretsService secrets.Service, secrets
|
|||||||
tracer := tracing.InitializeTracerForTest()
|
tracer := tracing.InitializeTracerForTest()
|
||||||
|
|
||||||
var routes []*plugins.Route
|
var routes []*plugins.Route
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(test.datasource, routes, ctx, "", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -1101,9 +1045,7 @@ func Test_PathCheck(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
proxy, err := NewDataSourceProxy(&datasources.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
proxy, err := NewDataSourceProxy(&datasources.DataSource{}, routes, ctx, "b", &setting.Cfg{}, httpclient.NewProvider(), &oauthtoken.Service{}, dsService, tracer)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) {
|
|||||||
PluginAdminExternalManageEnabled: tc.pluginAdminExternalManageEnabled,
|
PluginAdminExternalManageEnabled: tc.pluginAdminExternalManageEnabled,
|
||||||
}
|
}
|
||||||
hs.pluginInstaller = inst
|
hs.pluginInstaller = inst
|
||||||
hs.QuotaService = quotatest.New(false, nil)
|
hs.QuotaService = quotatest.NewQuotaServiceFake()
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run(testName("Install", tc), func(t *testing.T) {
|
t.Run(testName("Install", tc), func(t *testing.T) {
|
||||||
|
@ -6,22 +6,10 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
// swagger:route GET /org/quotas getCurrentOrg getCurrentOrgQuota
|
|
||||||
//
|
|
||||||
// Fetch Organization quota.
|
|
||||||
//
|
|
||||||
// If you are running Grafana Enterprise and have Fine-grained access control enabled, you need to have a permission with action `orgs.quotas:read` and scope `org:id:1` (orgIDScope).
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: getQuotaResponse
|
|
||||||
// 401: unauthorisedError
|
|
||||||
// 403: forbiddenError
|
|
||||||
// 404: notFoundError
|
|
||||||
// 500: internalServerError
|
|
||||||
func (hs *HTTPServer) GetCurrentOrgQuotas(c *models.ReqContext) response.Response {
|
func (hs *HTTPServer) GetCurrentOrgQuotas(c *models.ReqContext) response.Response {
|
||||||
return hs.getOrgQuotasHelper(c, c.OrgID)
|
return hs.getOrgQuotasHelper(c, c.OrgID)
|
||||||
}
|
}
|
||||||
@ -41,17 +29,22 @@ func (hs *HTTPServer) GetCurrentOrgQuotas(c *models.ReqContext) response.Respons
|
|||||||
func (hs *HTTPServer) GetOrgQuotas(c *models.ReqContext) response.Response {
|
func (hs *HTTPServer) GetOrgQuotas(c *models.ReqContext) response.Response {
|
||||||
orgId, err := strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64)
|
orgId, err := strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Err(quota.ErrBadRequest.Errorf("orgId is invalid: %w", err))
|
return response.Error(http.StatusBadRequest, "orgId is invalid", err)
|
||||||
}
|
}
|
||||||
return hs.getOrgQuotasHelper(c, orgId)
|
return hs.getOrgQuotasHelper(c, orgId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hs *HTTPServer) getOrgQuotasHelper(c *models.ReqContext, orgID int64) response.Response {
|
func (hs *HTTPServer) getOrgQuotasHelper(c *models.ReqContext, orgID int64) response.Response {
|
||||||
q, err := hs.QuotaService.GetQuotasByScope(c.Req.Context(), quota.OrgScope, orgID)
|
if !hs.Cfg.Quota.Enabled {
|
||||||
if err != nil {
|
return response.Error(404, "Quotas not enabled", nil)
|
||||||
return response.ErrOrFallback(http.StatusInternalServerError, "failed to get quota", err)
|
|
||||||
}
|
}
|
||||||
return response.JSON(http.StatusOK, q)
|
query := models.GetOrgQuotasQuery{OrgId: orgID}
|
||||||
|
|
||||||
|
if err := hs.SQLStore.GetOrgQuotas(c.Req.Context(), &query); err != nil {
|
||||||
|
return response.Error(500, "Failed to get org quotas", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(http.StatusOK, query.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route PUT /orgs/{org_id}/quotas/{quota_target} orgs updateOrgQuota
|
// swagger:route PUT /orgs/{org_id}/quotas/{quota_target} orgs updateOrgQuota
|
||||||
@ -70,19 +63,26 @@ func (hs *HTTPServer) getOrgQuotasHelper(c *models.ReqContext, orgID int64) resp
|
|||||||
// 404: notFoundError
|
// 404: notFoundError
|
||||||
// 500: internalServerError
|
// 500: internalServerError
|
||||||
func (hs *HTTPServer) UpdateOrgQuota(c *models.ReqContext) response.Response {
|
func (hs *HTTPServer) UpdateOrgQuota(c *models.ReqContext) response.Response {
|
||||||
cmd := quota.UpdateQuotaCmd{}
|
cmd := models.UpdateOrgQuotaCmd{}
|
||||||
var err error
|
var err error
|
||||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||||
return response.Err(quota.ErrBadRequest.Errorf("bad request data: %w", err))
|
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||||
}
|
}
|
||||||
cmd.OrgID, err = strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64)
|
if !hs.Cfg.Quota.Enabled {
|
||||||
|
return response.Error(404, "Quotas not enabled", nil)
|
||||||
|
}
|
||||||
|
cmd.OrgId, err = strconv.ParseInt(web.Params(c.Req)[":orgId"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Err(quota.ErrBadRequest.Errorf("orgId is invalid: %w", err))
|
return response.Error(http.StatusBadRequest, "orgId is invalid", err)
|
||||||
}
|
}
|
||||||
cmd.Target = web.Params(c.Req)[":target"]
|
cmd.Target = web.Params(c.Req)[":target"]
|
||||||
|
|
||||||
if err := hs.QuotaService.Update(c.Req.Context(), &cmd); err != nil {
|
if _, ok := hs.Cfg.Quota.Org.ToMap()[cmd.Target]; !ok {
|
||||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to update org quotas", err)
|
return response.Error(404, "Invalid quota target", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hs.SQLStore.UpdateOrgQuota(c.Req.Context(), &cmd); err != nil {
|
||||||
|
return response.Error(500, "Failed to update org quotas", err)
|
||||||
}
|
}
|
||||||
return response.Success("Organization quota updated")
|
return response.Success("Organization quota updated")
|
||||||
}
|
}
|
||||||
@ -114,17 +114,22 @@ func (hs *HTTPServer) UpdateOrgQuota(c *models.ReqContext) response.Response {
|
|||||||
// 404: notFoundError
|
// 404: notFoundError
|
||||||
// 500: internalServerError
|
// 500: internalServerError
|
||||||
func (hs *HTTPServer) GetUserQuotas(c *models.ReqContext) response.Response {
|
func (hs *HTTPServer) GetUserQuotas(c *models.ReqContext) response.Response {
|
||||||
|
if !setting.Quota.Enabled {
|
||||||
|
return response.Error(404, "Quotas not enabled", nil)
|
||||||
|
}
|
||||||
|
|
||||||
id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
|
id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Err(quota.ErrBadRequest.Errorf("id is invalid: %w", err))
|
return response.Error(http.StatusBadRequest, "id is invalid", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
q, err := hs.QuotaService.GetQuotasByScope(c.Req.Context(), quota.UserScope, id)
|
query := models.GetUserQuotasQuery{UserId: id}
|
||||||
if err != nil {
|
|
||||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to get org quotas", err)
|
if err := hs.SQLStore.GetUserQuotas(c.Req.Context(), &query); err != nil {
|
||||||
|
return response.Error(500, "Failed to get org quotas", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.JSON(http.StatusOK, q)
|
return response.JSON(http.StatusOK, query.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route PUT /admin/users/{user_id}/quotas/{quota_target} admin_users updateUserQuota
|
// swagger:route PUT /admin/users/{user_id}/quotas/{quota_target} admin_users updateUserQuota
|
||||||
@ -143,19 +148,26 @@ func (hs *HTTPServer) GetUserQuotas(c *models.ReqContext) response.Response {
|
|||||||
// 404: notFoundError
|
// 404: notFoundError
|
||||||
// 500: internalServerError
|
// 500: internalServerError
|
||||||
func (hs *HTTPServer) UpdateUserQuota(c *models.ReqContext) response.Response {
|
func (hs *HTTPServer) UpdateUserQuota(c *models.ReqContext) response.Response {
|
||||||
cmd := quota.UpdateQuotaCmd{}
|
cmd := models.UpdateUserQuotaCmd{}
|
||||||
var err error
|
var err error
|
||||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||||
return response.Err(quota.ErrBadRequest.Errorf("bad request data: %w", err))
|
return response.Error(http.StatusBadRequest, "bad request data", err)
|
||||||
}
|
}
|
||||||
cmd.UserID, err = strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
|
if !setting.Quota.Enabled {
|
||||||
|
return response.Error(404, "Quotas not enabled", nil)
|
||||||
|
}
|
||||||
|
cmd.UserId, err = strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Err(quota.ErrBadRequest.Errorf("id is invalid: %w", err))
|
return response.Error(http.StatusBadRequest, "id is invalid", err)
|
||||||
}
|
}
|
||||||
cmd.Target = web.Params(c.Req)[":target"]
|
cmd.Target = web.Params(c.Req)[":target"]
|
||||||
|
|
||||||
if err := hs.QuotaService.Update(c.Req.Context(), &cmd); err != nil {
|
if _, ok := setting.Quota.User.ToMap()[cmd.Target]; !ok {
|
||||||
return response.ErrOrFallback(http.StatusInternalServerError, "Failed to update org quotas", err)
|
return response.Error(404, "Invalid quota target", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hs.SQLStore.UpdateUserQuota(c.Req.Context(), &cmd); err != nil {
|
||||||
|
return response.Error(500, "Failed to update org quotas", err)
|
||||||
}
|
}
|
||||||
return response.Success("Organization quota updated")
|
return response.Success("Organization quota updated")
|
||||||
}
|
}
|
||||||
@ -164,7 +176,7 @@ func (hs *HTTPServer) UpdateUserQuota(c *models.ReqContext) response.Response {
|
|||||||
type UpdateUserQuotaParams struct {
|
type UpdateUserQuotaParams struct {
|
||||||
// in:body
|
// in:body
|
||||||
// required:true
|
// required:true
|
||||||
Body quota.UpdateQuotaCmd `json:"body"`
|
Body models.UpdateUserQuotaCmd `json:"body"`
|
||||||
// in:path
|
// in:path
|
||||||
// required:true
|
// required:true
|
||||||
QuotaTarget string `json:"quota_target"`
|
QuotaTarget string `json:"quota_target"`
|
||||||
@ -191,7 +203,7 @@ type GetOrgQuotaParams struct {
|
|||||||
type UpdateOrgQuotaParam struct {
|
type UpdateOrgQuotaParam struct {
|
||||||
// in:body
|
// in:body
|
||||||
// required:true
|
// required:true
|
||||||
Body quota.UpdateQuotaCmd `json:"body"`
|
Body models.UpdateOrgQuotaCmd `json:"body"`
|
||||||
// in:path
|
// in:path
|
||||||
// required:true
|
// required:true
|
||||||
QuotaTarget string `json:"quota_target"`
|
QuotaTarget string `json:"quota_target"`
|
||||||
@ -203,5 +215,5 @@ type UpdateOrgQuotaParam struct {
|
|||||||
// swagger:response getQuotaResponse
|
// swagger:response getQuotaResponse
|
||||||
type GetQuotaResponseResponse struct {
|
type GetQuotaResponseResponse struct {
|
||||||
// in:body
|
// in:body
|
||||||
Body []*quota.QuotaDTO `json:"body"`
|
Body []*models.UserQuotaDTO `json:"body"`
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,17 @@ var testOrgQuota = setting.OrgQuota{
|
|||||||
func setupDBAndSettingsForAccessControlQuotaTests(t *testing.T, sc accessControlScenarioContext) {
|
func setupDBAndSettingsForAccessControlQuotaTests(t *testing.T, sc accessControlScenarioContext) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
sc.hs.Cfg.Quota.Enabled = true
|
||||||
|
sc.hs.Cfg.Quota.Org = &testOrgQuota
|
||||||
|
// Required while sqlstore quota.go relies on setting global variables
|
||||||
|
setting.Quota = sc.hs.Cfg.Quota
|
||||||
|
|
||||||
// Create two orgs with the context user
|
// Create two orgs with the context user
|
||||||
setupOrgsDBForAccessControlTests(t, sc.db, sc, 2)
|
setupOrgsDBForAccessControlTests(t, sc.db, sc, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIEndpoint_GetCurrentOrgQuotas_LegacyAccessControl(t *testing.T) {
|
func TestAPIEndpoint_GetCurrentOrgQuotas_LegacyAccessControl(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.Quota.Enabled = true
|
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
||||||
setInitCtxSignedInViewer(sc.initCtx)
|
setInitCtxSignedInViewer(sc.initCtx)
|
||||||
@ -58,9 +62,7 @@ func TestAPIEndpoint_GetCurrentOrgQuotas_LegacyAccessControl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIEndpoint_GetCurrentOrgQuotas_AccessControl(t *testing.T) {
|
func TestAPIEndpoint_GetCurrentOrgQuotas_AccessControl(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
sc := setupHTTPServer(t, true)
|
||||||
cfg.Quota.Enabled = true
|
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
|
||||||
setInitCtxSignedInViewer(sc.initCtx)
|
setInitCtxSignedInViewer(sc.initCtx)
|
||||||
|
|
||||||
setupDBAndSettingsForAccessControlQuotaTests(t, sc)
|
setupDBAndSettingsForAccessControlQuotaTests(t, sc)
|
||||||
@ -84,7 +86,6 @@ func TestAPIEndpoint_GetCurrentOrgQuotas_AccessControl(t *testing.T) {
|
|||||||
|
|
||||||
func TestAPIEndpoint_GetOrgQuotas_LegacyAccessControl(t *testing.T) {
|
func TestAPIEndpoint_GetOrgQuotas_LegacyAccessControl(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.Quota.Enabled = true
|
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
||||||
setInitCtxSignedInViewer(sc.initCtx)
|
setInitCtxSignedInViewer(sc.initCtx)
|
||||||
@ -104,9 +105,7 @@ func TestAPIEndpoint_GetOrgQuotas_LegacyAccessControl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIEndpoint_GetOrgQuotas_AccessControl(t *testing.T) {
|
func TestAPIEndpoint_GetOrgQuotas_AccessControl(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
sc := setupHTTPServer(t, true)
|
||||||
cfg.Quota.Enabled = true
|
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
|
||||||
setupDBAndSettingsForAccessControlQuotaTests(t, sc)
|
setupDBAndSettingsForAccessControlQuotaTests(t, sc)
|
||||||
|
|
||||||
t.Run("AccessControl allows viewing another org quotas with correct permissions", func(t *testing.T) {
|
t.Run("AccessControl allows viewing another org quotas with correct permissions", func(t *testing.T) {
|
||||||
@ -131,7 +130,6 @@ func TestAPIEndpoint_GetOrgQuotas_AccessControl(t *testing.T) {
|
|||||||
|
|
||||||
func TestAPIEndpoint_PutOrgQuotas_LegacyAccessControl(t *testing.T) {
|
func TestAPIEndpoint_PutOrgQuotas_LegacyAccessControl(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.Quota.Enabled = true
|
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
sc := setupHTTPServerWithCfg(t, true, cfg)
|
||||||
setInitCtxSignedInViewer(sc.initCtx)
|
setInitCtxSignedInViewer(sc.initCtx)
|
||||||
@ -153,20 +151,7 @@ func TestAPIEndpoint_PutOrgQuotas_LegacyAccessControl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIEndpoint_PutOrgQuotas_AccessControl(t *testing.T) {
|
func TestAPIEndpoint_PutOrgQuotas_AccessControl(t *testing.T) {
|
||||||
cfg := setting.NewCfg()
|
sc := setupHTTPServer(t, true)
|
||||||
cfg.Quota = setting.QuotaSettings{
|
|
||||||
Enabled: true,
|
|
||||||
Global: setting.GlobalQuota{
|
|
||||||
Org: 5,
|
|
||||||
},
|
|
||||||
Org: setting.OrgQuota{
|
|
||||||
User: 5,
|
|
||||||
},
|
|
||||||
User: setting.UserQuota{
|
|
||||||
Org: 5,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
sc := setupHTTPServerWithCfg(t, true, cfg)
|
|
||||||
setupDBAndSettingsForAccessControlQuotaTests(t, sc)
|
setupDBAndSettingsForAccessControlQuotaTests(t, sc)
|
||||||
|
|
||||||
input := strings.NewReader(testUpdateOrgQuotaCmd)
|
input := strings.NewReader(testUpdateOrgQuotaCmd)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/login/authinfoservice"
|
"github.com/grafana/grafana/pkg/services/login/authinfoservice"
|
||||||
authinfostore "github.com/grafana/grafana/pkg/services/login/authinfoservice/database"
|
authinfostore "github.com/grafana/grafana/pkg/services/login/authinfoservice/database"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/searchusers"
|
"github.com/grafana/grafana/pkg/services/searchusers"
|
||||||
"github.com/grafana/grafana/pkg/services/searchusers/filters"
|
"github.com/grafana/grafana/pkg/services/searchusers/filters"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||||
@ -69,8 +68,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
user, err := sqlStore.CreateUser(context.Background(), createUserCmd)
|
user, err := sqlStore.CreateUser(context.Background(), createUserCmd)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
hs.userService, err = userimpl.ProvideService(sqlStore, nil, sc.cfg, nil, nil, quotatest.New(false, nil))
|
hs.userService = userimpl.ProvideService(sqlStore, nil, sc.cfg, nil, nil)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
sc.handlerFunc = hs.GetUserByID
|
sc.handlerFunc = hs.GetUserByID
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ var wireSet = wire.NewSet(
|
|||||||
wire.Bind(new(social.Service), new(*social.SocialService)),
|
wire.Bind(new(social.Service), new(*social.SocialService)),
|
||||||
oauthtoken.ProvideService,
|
oauthtoken.ProvideService,
|
||||||
auth.ProvideActiveAuthTokenService,
|
auth.ProvideActiveAuthTokenService,
|
||||||
wire.Bind(new(auth.ActiveTokenService), new(*auth.ActiveAuthTokenService)),
|
wire.Bind(new(models.ActiveTokenService), new(*auth.ActiveAuthTokenService)),
|
||||||
wire.Bind(new(oauthtoken.OAuthTokenService), new(*oauthtoken.Service)),
|
wire.Bind(new(oauthtoken.OAuthTokenService), new(*oauthtoken.Service)),
|
||||||
tempo.ProvideService,
|
tempo.ProvideService,
|
||||||
loki.ProvideService,
|
loki.ProvideService,
|
||||||
|
@ -14,15 +14,15 @@ func Quota(quotaService quota.Service) func(string) web.Handler {
|
|||||||
panic("quotaService is nil")
|
panic("quotaService is nil")
|
||||||
}
|
}
|
||||||
//https://open.spotify.com/track/7bZSoBEAEEUsGEuLOf94Jm?si=T1Tdju5qRSmmR0zph_6RBw fuuuuunky
|
//https://open.spotify.com/track/7bZSoBEAEEUsGEuLOf94Jm?si=T1Tdju5qRSmmR0zph_6RBw fuuuuunky
|
||||||
return func(targetSrv string) web.Handler {
|
return func(target string) web.Handler {
|
||||||
return func(c *models.ReqContext) {
|
return func(c *models.ReqContext) {
|
||||||
limitReached, err := quotaService.QuotaReached(c, quota.TargetSrv(targetSrv))
|
limitReached, err := quotaService.QuotaReached(c, target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JsonApiErr(500, "Failed to get quota", err)
|
c.JsonApiErr(500, "Failed to get quota", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if limitReached {
|
if limitReached {
|
||||||
c.JsonApiErr(403, fmt.Sprintf("%s Quota reached", targetSrv), nil)
|
c.JsonApiErr(403, fmt.Sprintf("%s Quota reached", target), nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
@ -30,6 +30,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 403, sc.resp.Code)
|
assert.Equal(t, 403, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Global.User = 4
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "and global session quota not reached", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "and global session quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -39,6 +41,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 200, sc.resp.Code)
|
assert.Equal(t, 200, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Global.Session = 10
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "and global session quota reached", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "and global session quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -48,10 +52,13 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 403, sc.resp.Code)
|
assert.Equal(t, 403, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Global.Session = 1
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with user logged in", func(t *testing.T) {
|
t.Run("with user logged in", func(t *testing.T) {
|
||||||
|
const quotaUsed = 4
|
||||||
setUp := func(sc *scenarioContext) {
|
setUp := func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
sc.userService.ExpectedSignedInUser = &user.SignedInUser{UserID: 12}
|
sc.userService.ExpectedSignedInUser = &user.SignedInUser{UserID: 12}
|
||||||
@ -72,6 +79,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 403, sc.resp.Code)
|
assert.Equal(t, 403, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Global.DataSource = quotaUsed
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "user Org quota not reached", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "user Org quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -84,6 +93,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 200, sc.resp.Code)
|
assert.Equal(t, 200, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.User.Org = quotaUsed + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "user Org quota reached", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "user Org quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -95,6 +106,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 403, sc.resp.Code)
|
assert.Equal(t, 403, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.User.Org = quotaUsed
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org dashboard quota not reached", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org dashboard quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -106,6 +119,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 200, sc.resp.Code)
|
assert.Equal(t, 200, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Org.Dashboard = quotaUsed + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org dashboard quota reached", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org dashboard quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -117,6 +132,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 403, sc.resp.Code)
|
assert.Equal(t, 403, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Org.Dashboard = quotaUsed
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org dashboard quota reached, but quotas disabled", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org dashboard quota reached, but quotas disabled", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -128,6 +145,9 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 200, sc.resp.Code)
|
assert.Equal(t, 200, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Org.Dashboard = quotaUsed
|
||||||
|
cfg.Quota.Enabled = false
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org alert quota reached and unified alerting is enabled", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org alert quota reached and unified alerting is enabled", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -142,6 +162,7 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
|
|
||||||
cfg.UnifiedAlerting.Enabled = new(bool)
|
cfg.UnifiedAlerting.Enabled = new(bool)
|
||||||
*cfg.UnifiedAlerting.Enabled = true
|
*cfg.UnifiedAlerting.Enabled = true
|
||||||
|
cfg.Quota.Org.AlertRule = quotaUsed
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org alert quota not reached and unified alerting is enabled", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org alert quota not reached and unified alerting is enabled", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -156,6 +177,7 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
|
|
||||||
cfg.UnifiedAlerting.Enabled = new(bool)
|
cfg.UnifiedAlerting.Enabled = new(bool)
|
||||||
*cfg.UnifiedAlerting.Enabled = true
|
*cfg.UnifiedAlerting.Enabled = true
|
||||||
|
cfg.Quota.Org.AlertRule = quotaUsed + 1
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org alert quota reached but ngalert disabled", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org alert quota reached but ngalert disabled", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -168,6 +190,8 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 403, sc.resp.Code)
|
assert.Equal(t, 403, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Org.AlertRule = quotaUsed
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario(t, "org alert quota not reached but ngalert disabled", func(t *testing.T, sc *scenarioContext) {
|
middlewareScenario(t, "org alert quota not reached but ngalert disabled", func(t *testing.T, sc *scenarioContext) {
|
||||||
@ -179,15 +203,58 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
assert.Equal(t, 200, sc.resp.Code)
|
assert.Equal(t, 200, sc.resp.Code)
|
||||||
}, func(cfg *setting.Cfg) {
|
}, func(cfg *setting.Cfg) {
|
||||||
configure(cfg)
|
configure(cfg)
|
||||||
|
|
||||||
|
cfg.Quota.Org.AlertRule = quotaUsed + 1
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getQuotaHandler(reached bool, target string) web.Handler {
|
func getQuotaHandler(reached bool, target string) web.Handler {
|
||||||
qs := quotatest.New(reached, nil)
|
qs := &mockQuotaService{
|
||||||
|
reached: reached,
|
||||||
|
}
|
||||||
return Quota(qs)(target)
|
return Quota(qs)(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configure(cfg *setting.Cfg) {
|
func configure(cfg *setting.Cfg) {
|
||||||
cfg.AnonymousEnabled = false
|
cfg.AnonymousEnabled = false
|
||||||
|
cfg.Quota = setting.QuotaSettings{
|
||||||
|
Enabled: true,
|
||||||
|
Org: &setting.OrgQuota{
|
||||||
|
User: 5,
|
||||||
|
Dashboard: 5,
|
||||||
|
DataSource: 5,
|
||||||
|
ApiKey: 5,
|
||||||
|
AlertRule: 5,
|
||||||
|
},
|
||||||
|
User: &setting.UserQuota{
|
||||||
|
Org: 5,
|
||||||
|
},
|
||||||
|
Global: &setting.GlobalQuota{
|
||||||
|
Org: 5,
|
||||||
|
User: 5,
|
||||||
|
Dashboard: 5,
|
||||||
|
DataSource: 5,
|
||||||
|
ApiKey: 5,
|
||||||
|
Session: 5,
|
||||||
|
AlertRule: 5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockQuotaService struct {
|
||||||
|
reached bool
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockQuotaService) QuotaReached(c *models.ReqContext, target string) (bool, error) {
|
||||||
|
return m.reached, m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockQuotaService) CheckQuotaReached(c context.Context, target string, params *quota.ScopeParameters) (bool, error) {
|
||||||
|
return m.reached, m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockQuotaService) DeleteByUser(c context.Context, userID int64) error {
|
||||||
|
return m.err
|
||||||
}
|
}
|
||||||
|
91
pkg/models/quotas.go
Normal file
91
pkg/models/quotas.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrInvalidQuotaTarget = errors.New("invalid quota target")
|
||||||
|
|
||||||
|
type Quota struct {
|
||||||
|
Id int64
|
||||||
|
OrgId int64
|
||||||
|
UserId int64
|
||||||
|
Target string
|
||||||
|
Limit int64
|
||||||
|
Created time.Time
|
||||||
|
Updated time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type QuotaScope struct {
|
||||||
|
Name string
|
||||||
|
Target string
|
||||||
|
DefaultLimit int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrgQuotaDTO struct {
|
||||||
|
OrgId int64 `json:"org_id"`
|
||||||
|
Target string `json:"target"`
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
|
Used int64 `json:"used"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserQuotaDTO struct {
|
||||||
|
UserId int64 `json:"user_id"`
|
||||||
|
Target string `json:"target"`
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
|
Used int64 `json:"used"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GlobalQuotaDTO struct {
|
||||||
|
Target string `json:"target"`
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
|
Used int64 `json:"used"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetOrgQuotaByTargetQuery struct {
|
||||||
|
Target string
|
||||||
|
OrgId int64
|
||||||
|
Default int64
|
||||||
|
UnifiedAlertingEnabled bool
|
||||||
|
Result *OrgQuotaDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetOrgQuotasQuery struct {
|
||||||
|
OrgId int64
|
||||||
|
UnifiedAlertingEnabled bool
|
||||||
|
Result []*OrgQuotaDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserQuotaByTargetQuery struct {
|
||||||
|
Target string
|
||||||
|
UserId int64
|
||||||
|
Default int64
|
||||||
|
UnifiedAlertingEnabled bool
|
||||||
|
Result *UserQuotaDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetUserQuotasQuery struct {
|
||||||
|
UserId int64
|
||||||
|
UnifiedAlertingEnabled bool
|
||||||
|
Result []*UserQuotaDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetGlobalQuotaByTargetQuery struct {
|
||||||
|
Target string
|
||||||
|
Default int64
|
||||||
|
UnifiedAlertingEnabled bool
|
||||||
|
Result *GlobalQuotaDTO
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateOrgQuotaCmd struct {
|
||||||
|
Target string `json:"target"`
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
|
OrgId int64 `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateUserQuotaCmd struct {
|
||||||
|
Target string `json:"target"`
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
|
UserId int64 `json:"-"`
|
||||||
|
}
|
@ -76,6 +76,10 @@ type UserTokenService interface {
|
|||||||
GetUserRevokedTokens(ctx context.Context, userId int64) ([]*UserToken, error)
|
GetUserRevokedTokens(ctx context.Context, userId int64) ([]*UserToken, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ActiveTokenService interface {
|
||||||
|
ActiveTokenCount(ctx context.Context) (int64, error)
|
||||||
|
}
|
||||||
|
|
||||||
type UserTokenBackgroundService interface {
|
type UserTokenBackgroundService interface {
|
||||||
registry.BackgroundService
|
registry.BackgroundService
|
||||||
}
|
}
|
||||||
|
@ -272,7 +272,7 @@ var wireBasicSet = wire.NewSet(
|
|||||||
wire.Bind(new(social.Service), new(*social.SocialService)),
|
wire.Bind(new(social.Service), new(*social.SocialService)),
|
||||||
oauthtoken.ProvideService,
|
oauthtoken.ProvideService,
|
||||||
auth.ProvideActiveAuthTokenService,
|
auth.ProvideActiveAuthTokenService,
|
||||||
wire.Bind(new(auth.ActiveTokenService), new(*auth.ActiveAuthTokenService)),
|
wire.Bind(new(models.ActiveTokenService), new(*auth.ActiveAuthTokenService)),
|
||||||
wire.Bind(new(oauthtoken.OAuthTokenService), new(*oauthtoken.Service)),
|
wire.Bind(new(oauthtoken.OAuthTokenService), new(*oauthtoken.Service)),
|
||||||
tempo.ProvideService,
|
tempo.ProvideService,
|
||||||
loki.ProvideService,
|
loki.ProvideService,
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/team"
|
"github.com/grafana/grafana/pkg/services/team"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
||||||
@ -226,8 +225,7 @@ func setupTestEnvironment(t *testing.T, permissions []accesscontrol.Permission,
|
|||||||
sql := db.InitTestDB(t)
|
sql := db.InitTestDB(t)
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
teamSvc := teamimpl.ProvideService(sql, cfg)
|
teamSvc := teamimpl.ProvideService(sql, cfg)
|
||||||
userSvc, err := userimpl.ProvideService(sql, nil, cfg, teamimpl.ProvideService(sql, cfg), nil, quotatest.New(false, nil))
|
userSvc := userimpl.ProvideService(sql, nil, cfg, teamimpl.ProvideService(sql, cfg), nil)
|
||||||
require.NoError(t, err)
|
|
||||||
license := licensingtest.NewFakeLicensing()
|
license := licensingtest.NewFakeLicensing()
|
||||||
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
||||||
mock := accesscontrolmock.New().WithPermissions(permissions)
|
mock := accesscontrolmock.New().WithPermissions(permissions)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -57,9 +56,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardstore.ProvideDashboardStore(sql, sql.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql, sql.Cfg))
|
||||||
dashboardStore, err := dashboardstore.ProvideDashboardStore(sql, sql.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql, sql.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testDashboard1 := models.SaveDashboardCommand{
|
testDashboard1 := models.SaveDashboardCommand{
|
||||||
UserId: 1,
|
UserId: 1,
|
||||||
@ -456,9 +453,7 @@ func TestIntegrationAnnotationListingWithRBAC(t *testing.T) {
|
|||||||
|
|
||||||
var maximumTagsLength int64 = 60
|
var maximumTagsLength int64 = 60
|
||||||
repo := xormRepositoryImpl{db: sql, cfg: setting.NewCfg(), log: log.New("annotation.test"), tagService: tagimpl.ProvideService(sql, sql.Cfg), maximumTagsLength: maximumTagsLength}
|
repo := xormRepositoryImpl{db: sql, cfg: setting.NewCfg(), log: log.New("annotation.test"), tagService: tagimpl.ProvideService(sql, sql.Cfg), maximumTagsLength: maximumTagsLength}
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardstore.ProvideDashboardStore(sql, sql.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql, sql.Cfg))
|
||||||
dashboardStore, err := dashboardstore.ProvideDashboardStore(sql, sql.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sql, sql.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testDashboard1 := models.SaveDashboardCommand{
|
testDashboard1 := models.SaveDashboardCommand{
|
||||||
UserId: 1,
|
UserId: 1,
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,34 +13,16 @@ type Service struct {
|
|||||||
store store
|
store store
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(db db.DB, cfg *setting.Cfg, quotaService quota.Service) (apikey.Service, error) {
|
func ProvideService(db db.DB, cfg *setting.Cfg) apikey.Service {
|
||||||
s := &Service{}
|
|
||||||
if cfg.IsFeatureToggleEnabled(featuremgmt.FlagNewDBLibrary) {
|
if cfg.IsFeatureToggleEnabled(featuremgmt.FlagNewDBLibrary) {
|
||||||
s.store = &sqlxStore{
|
return &Service{
|
||||||
|
store: &sqlxStore{
|
||||||
sess: db.GetSqlxSession(),
|
sess: db.GetSqlxSession(),
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.store = &sqlStore{db: db, cfg: cfg}
|
return &Service{store: &sqlStore{db: db, cfg: cfg}}
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: apikey.QuotaTargetSrv,
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.Usage,
|
|
||||||
}); err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Usage(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
return s.store.Count(ctx, scopeParams)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) error {
|
func (s *Service) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) error {
|
||||||
@ -68,24 +49,3 @@ func (s *Service) AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) error {
|
|||||||
func (s *Service) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error {
|
func (s *Service) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error {
|
||||||
return s.store.UpdateAPIKeyLastUsedDate(ctx, tokenID)
|
return s.store.UpdateAPIKeyLastUsedDate(ctx, tokenID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
orgQuotaTag, err := quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.ApiKey)
|
|
||||||
limits.Set(orgQuotaTag, cfg.Quota.Org.ApiKey)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/session"
|
"github.com/grafana/grafana/pkg/services/sqlstore/session"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
@ -143,35 +142,3 @@ func (ss *sqlxStore) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64
|
|||||||
_, err := ss.sess.Exec(ctx, `UPDATE api_key SET last_used_at=? WHERE id=?`, &now, tokenID)
|
_, err := ss.sess.Exec(ctx, `UPDATE api_key SET last_used_at=? WHERE id=?`, &now, tokenID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlxStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
if err := ss.sess.Get(ctx, &r, `SELECT COUNT(*) AS count FROM api_key`); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.OrgID != 0 {
|
|
||||||
if err := ss.sess.Get(ctx, &r, `SELECT COUNT(*) AS count FROM api_key WHERE org_id = ?`, scopeParams.OrgID); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
@ -16,6 +15,4 @@ type store interface {
|
|||||||
GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQuery) error
|
GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQuery) error
|
||||||
GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error)
|
GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error)
|
||||||
UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error
|
UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error
|
||||||
|
|
||||||
Count(context.Context, *quota.ScopeParameters) (*quota.Map, error)
|
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -176,47 +174,3 @@ func (ss *sqlStore) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64)
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := "SELECT COUNT(*) AS count FROM api_key"
|
|
||||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.OrgID != 0 {
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := "SELECT COUNT(*) AS count FROM api_key WHERE org_id = ?"
|
|
||||||
if _, err := sess.SQL(rawSQL, scopeParams.OrgID).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,8 +64,3 @@ type GetByIDQuery struct {
|
|||||||
ApiKeyId int64
|
ApiKeyId int64
|
||||||
Result *APIKey
|
Result *APIKey
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv quota.TargetSrv = "api_key"
|
|
||||||
QuotaTarget quota.Target = "api_key"
|
|
||||||
)
|
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/infra/serverlock"
|
"github.com/grafana/grafana/pkg/infra/serverlock"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
@ -42,38 +41,19 @@ type UserAuthTokenService struct {
|
|||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActiveTokenService interface {
|
|
||||||
ActiveTokenCount(ctx context.Context, _ *quota.ScopeParameters) (*quota.Map, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActiveAuthTokenService struct {
|
type ActiveAuthTokenService struct {
|
||||||
cfg *setting.Cfg
|
cfg *setting.Cfg
|
||||||
sqlStore db.DB
|
sqlStore db.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideActiveAuthTokenService(cfg *setting.Cfg, sqlStore db.DB, quotaService quota.Service) (*ActiveAuthTokenService, error) {
|
func ProvideActiveAuthTokenService(cfg *setting.Cfg, sqlStore db.DB) *ActiveAuthTokenService {
|
||||||
s := &ActiveAuthTokenService{
|
return &ActiveAuthTokenService{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
sqlStore: sqlStore,
|
sqlStore: sqlStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
func (a *ActiveAuthTokenService) ActiveTokenCount(ctx context.Context) (int64, error) {
|
||||||
TargetSrv: QuotaTargetSrv,
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.ActiveTokenCount,
|
|
||||||
}); err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ActiveAuthTokenService) ActiveTokenCount(ctx context.Context, _ *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
var count int64
|
var count int64
|
||||||
var err error
|
var err error
|
||||||
err = a.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
err = a.sqlStore.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||||
@ -86,14 +66,7 @@ func (a *ActiveAuthTokenService) ActiveTokenCount(ctx context.Context, _ *quota.
|
|||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
tag, err := quota.NewTag(QuotaTargetSrv, QuotaTarget, quota.GlobalScope)
|
return count, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u := "a.Map{}
|
|
||||||
u.Set(tag, count)
|
|
||||||
|
|
||||||
return u, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*models.UserToken, error) {
|
func (s *UserAuthTokenService) CreateToken(ctx context.Context, user *user.User, clientIP net.IP, userAgent string) (*models.UserToken, error) {
|
||||||
@ -499,19 +472,3 @@ func hashToken(token string) string {
|
|||||||
hashBytes := sha256.Sum256([]byte(token + setting.SecretKey))
|
hashBytes := sha256.Sum256([]byte(token + setting.SecretKey))
|
||||||
return hex.EncodeToString(hashBytes[:])
|
return hex.EncodeToString(hashBytes[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(QuotaTargetSrv, QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.Session)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
@ -41,12 +40,8 @@ func TestUserAuthToken(t *testing.T) {
|
|||||||
userToken := createToken()
|
userToken := createToken()
|
||||||
|
|
||||||
t.Run("Can count active tokens", func(t *testing.T) {
|
t.Run("Can count active tokens", func(t *testing.T) {
|
||||||
m, err := ctx.activeTokenService.ActiveTokenCount(context.Background(), "a.ScopeParameters{})
|
count, err := ctx.activeTokenService.ActiveTokenCount(context.Background())
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
tag, err := quota.NewTag(QuotaTargetSrv, QuotaTarget, quota.GlobalScope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
count, ok := m.Get(tag)
|
|
||||||
require.True(t, ok)
|
|
||||||
require.Equal(t, int64(1), count)
|
require.Equal(t, int64(1), count)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -213,12 +208,8 @@ func TestUserAuthToken(t *testing.T) {
|
|||||||
require.Nil(t, notGood)
|
require.Nil(t, notGood)
|
||||||
|
|
||||||
t.Run("should not find active token when expired", func(t *testing.T) {
|
t.Run("should not find active token when expired", func(t *testing.T) {
|
||||||
m, err := ctx.activeTokenService.ActiveTokenCount(context.Background(), "a.ScopeParameters{})
|
count, err := ctx.activeTokenService.ActiveTokenCount(context.Background())
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
tag, err := quota.NewTag(QuotaTargetSrv, QuotaTarget, quota.GlobalScope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
count, ok := m.Get(tag)
|
|
||||||
require.True(t, ok)
|
|
||||||
require.Equal(t, int64(0), count)
|
require.Equal(t, int64(0), count)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type userAuthToken struct {
|
type userAuthToken struct {
|
||||||
@ -72,8 +71,3 @@ func (uat *userAuthToken) toUserToken(ut *models.UserToken) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv quota.TargetSrv = "auth"
|
|
||||||
QuotaTarget quota.Target = "session"
|
|
||||||
)
|
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboardimport"
|
"github.com/grafana/grafana/pkg/services/dashboardimport"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,9 +64,9 @@ func (api *ImportDashboardAPI) ImportDashboard(c *models.ReqContext) response.Re
|
|||||||
return response.Error(http.StatusUnprocessableEntity, "Dashboard must be set", nil)
|
return response.Error(http.StatusUnprocessableEntity, "Dashboard must be set", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
limitReached, err := api.quotaService.QuotaReached(c, dashboards.QuotaTargetSrv)
|
limitReached, err := api.quotaService.QuotaReached(c, "dashboard")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Err(err)
|
return response.Error(500, "failed to get quota", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if limitReached {
|
if limitReached {
|
||||||
@ -84,12 +83,12 @@ func (api *ImportDashboardAPI) ImportDashboard(c *models.ReqContext) response.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
type QuotaService interface {
|
type QuotaService interface {
|
||||||
QuotaReached(c *models.ReqContext, target quota.TargetSrv) (bool, error)
|
QuotaReached(c *models.ReqContext, target string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type quotaServiceFunc func(c *models.ReqContext, target quota.TargetSrv) (bool, error)
|
type quotaServiceFunc func(c *models.ReqContext, target string) (bool, error)
|
||||||
|
|
||||||
func (fn quotaServiceFunc) QuotaReached(c *models.ReqContext, target quota.TargetSrv) (bool, error) {
|
func (fn quotaServiceFunc) QuotaReached(c *models.ReqContext, target string) (bool, error) {
|
||||||
return fn(c, target)
|
return fn(c, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboardimport"
|
"github.com/grafana/grafana/pkg/services/dashboardimport"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/web/webtest"
|
"github.com/grafana/grafana/pkg/web/webtest"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -166,10 +165,10 @@ func (s *serviceMock) ImportDashboard(ctx context.Context, req *dashboardimport.
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func quotaReached(c *models.ReqContext, target quota.TargetSrv) (bool, error) {
|
func quotaReached(c *models.ReqContext, target string) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func quotaNotReached(c *models.ReqContext, target quota.TargetSrv) (bool, error) {
|
func quotaNotReached(c *models.ReqContext, target string) (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DashboardService is a service for operating on dashboards.
|
// DashboardService is a service for operating on dashboards.
|
||||||
@ -78,7 +77,6 @@ type Store interface {
|
|||||||
ValidateDashboardBeforeSave(ctx context.Context, dashboard *models.Dashboard, overwrite bool) (bool, error)
|
ValidateDashboardBeforeSave(ctx context.Context, dashboard *models.Dashboard, overwrite bool) (bool, error)
|
||||||
DeleteACLByUser(context.Context, int64) error
|
DeleteACLByUser(context.Context, int64) error
|
||||||
|
|
||||||
Count(context.Context, *quota.ScopeParameters) (*quota.Map, error)
|
|
||||||
// CountDashboardsInFolder returns the number of dashboards associated with
|
// CountDashboardsInFolder returns the number of dashboards associated with
|
||||||
// the given parent folder ID.
|
// the given parent folder ID.
|
||||||
CountDashboardsInFolder(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error)
|
CountDashboardsInFolder(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error)
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
||||||
@ -27,10 +26,7 @@ func TestIntegrationDashboardACLDataAccess(t *testing.T) {
|
|||||||
|
|
||||||
setup := func(t *testing.T) {
|
setup := func(t *testing.T) {
|
||||||
sqlStore = db.InitTestDB(t)
|
sqlStore = db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
var err error
|
|
||||||
dashboardStore, err = ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
currentUser = createUser(t, sqlStore, "viewer", "Viewer", false)
|
currentUser = createUser(t, sqlStore, "viewer", "Viewer", false)
|
||||||
savedFolder = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
|
savedFolder = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
|
||||||
childDash = insertTestDashboard(t, dashboardStore, "2 test dash", 1, savedFolder.Id, false, "prod", "webapp")
|
childDash = insertTestDashboard(t, dashboardStore, "2 test dash", 1, savedFolder.Id, false, "prod", "webapp")
|
||||||
|
@ -16,8 +16,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||||
@ -44,23 +42,8 @@ type DashboardTag struct {
|
|||||||
// DashboardStore implements the Store interface
|
// DashboardStore implements the Store interface
|
||||||
var _ dashboards.Store = (*DashboardStore)(nil)
|
var _ dashboards.Store = (*DashboardStore)(nil)
|
||||||
|
|
||||||
func ProvideDashboardStore(sqlStore db.DB, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tagService tag.Service, quotaService quota.Service) (*DashboardStore, error) {
|
func ProvideDashboardStore(sqlStore db.DB, cfg *setting.Cfg, features featuremgmt.FeatureToggles, tagService tag.Service) *DashboardStore {
|
||||||
s := &DashboardStore{store: sqlStore, cfg: cfg, log: log.New("dashboard-store"), features: features, tagService: tagService}
|
return &DashboardStore{store: sqlStore, cfg: cfg, log: log.New("dashboard-store"), features: features, tagService: tagService}
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: dashboards.QuotaTargetSrv,
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.Count,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DashboardStore) emitEntityEvent() bool {
|
func (d *DashboardStore) emitEntityEvent() bool {
|
||||||
@ -308,50 +291,6 @@ func (d *DashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Context
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DashboardStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
if err := d.store.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM dashboard WHERE is_folder=%s", d.store.GetDialect().BooleanStr(false))
|
|
||||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.OrgID != 0 {
|
|
||||||
if err := d.store.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM dashboard WHERE org_id=? AND is_folder=%s", d.store.GetDialect().BooleanStr(false))
|
|
||||||
if _, err := sess.SQL(rawSQL, scopeParams.OrgID).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getExistingDashboardByIdOrUidForUpdate(sess *db.Session, dash *models.Dashboard, dialect migrator.Dialect, overwrite bool) (bool, error) {
|
func getExistingDashboardByIdOrUidForUpdate(sess *db.Session, dash *models.Dashboard, dialect migrator.Dialect, overwrite bool) (bool, error) {
|
||||||
dashWithIdExists := false
|
dashWithIdExists := false
|
||||||
isParentFolderChanged := false
|
isParentFolderChanged := false
|
||||||
@ -1079,27 +1018,6 @@ func (d *DashboardStore) GetDashboardTags(ctx context.Context, query *models.Get
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return "a.Map{}, err
|
|
||||||
}
|
|
||||||
orgQuotaTag, err := quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return "a.Map{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.Dashboard)
|
|
||||||
limits.Set(orgQuotaTag, cfg.Quota.Org.Dashboard)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will be updated to take CountDashboardsInFolderQuery as an argument and
|
// This will be updated to take CountDashboardsInFolderQuery as an argument and
|
||||||
// lookup dashboards using the ParentFolderUID when the NestedFolder
|
// lookup dashboards using the ParentFolderUID when the NestedFolder
|
||||||
// implementation is complete.
|
// implementation is complete.
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -34,10 +33,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
|
|||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore = db.InitTestDB(t)
|
sqlStore = db.InitTestDB(t)
|
||||||
sqlStore.Cfg.RBACEnabled = false
|
sqlStore.Cfg.RBACEnabled = false
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = ProvideDashboardStore(sqlStore, &setting.Cfg{}, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
var err error
|
|
||||||
dashboardStore, err = ProvideDashboardStore(sqlStore, &setting.Cfg{}, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
folder = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
|
folder = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
|
||||||
dashInRoot = insertTestDashboard(t, dashboardStore, "test dash 67", 1, 0, false, "prod", "webapp")
|
dashInRoot = insertTestDashboard(t, dashboardStore, "test dash 67", 1, 0, false, "prod", "webapp")
|
||||||
childDash = insertTestDashboard(t, dashboardStore, "test dash 23", 1, folder.Id, false, "prod", "webapp")
|
childDash = insertTestDashboard(t, dashboardStore, "test dash 23", 1, folder.Id, false, "prod", "webapp")
|
||||||
@ -190,9 +186,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
|
|||||||
|
|
||||||
setup2 := func() {
|
setup2 := func() {
|
||||||
sqlStore = db.InitTestDB(t)
|
sqlStore = db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
folder1 = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod")
|
folder1 = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod")
|
||||||
folder2 = insertTestDashboard(t, dashboardStore, "2 test dash folder", 1, 0, true, "prod")
|
folder2 = insertTestDashboard(t, dashboardStore, "2 test dash folder", 1, 0, true, "prod")
|
||||||
dashInRoot = insertTestDashboard(t, dashboardStore, "test dash 67", 1, 0, false, "prod")
|
dashInRoot = insertTestDashboard(t, dashboardStore, "test dash 67", 1, 0, false, "prod")
|
||||||
@ -297,9 +291,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
|
|||||||
|
|
||||||
setup3 := func() {
|
setup3 := func() {
|
||||||
sqlStore = db.InitTestDB(t)
|
sqlStore = db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
folder1 = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod")
|
folder1 = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod")
|
||||||
folder2 = insertTestDashboard(t, dashboardStore, "2 test dash folder", 1, 0, true, "prod")
|
folder2 = insertTestDashboard(t, dashboardStore, "2 test dash folder", 1, 0, true, "prod")
|
||||||
insertTestDashboard(t, dashboardStore, "folder in another org", 2, 0, true, "prod")
|
insertTestDashboard(t, dashboardStore, "folder in another org", 2, 0, true, "prod")
|
||||||
@ -481,9 +473,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
|
|||||||
var sqlStore *sqlstore.SQLStore
|
var sqlStore *sqlstore.SQLStore
|
||||||
var folder1, folder2 *models.Dashboard
|
var folder1, folder2 *models.Dashboard
|
||||||
sqlStore = db.InitTestDB(t)
|
sqlStore = db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
folder2 = insertTestDashboard(t, dashboardStore, "TEST", orgId, 0, true, "prod")
|
folder2 = insertTestDashboard(t, dashboardStore, "TEST", orgId, 0, true, "prod")
|
||||||
_ = insertTestDashboard(t, dashboardStore, title, orgId, folder2.Id, false, "prod")
|
_ = insertTestDashboard(t, dashboardStore, title, orgId, folder2.Id, false, "prod")
|
||||||
folder1 = insertTestDashboard(t, dashboardStore, title, orgId, 0, true, "prod")
|
folder1 = insertTestDashboard(t, dashboardStore, title, orgId, 0, true, "prod")
|
||||||
@ -498,9 +488,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
|
|||||||
t.Run("GetFolderByUID", func(t *testing.T) {
|
t.Run("GetFolderByUID", func(t *testing.T) {
|
||||||
var orgId int64 = 1
|
var orgId int64 = 1
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
folder := insertTestDashboard(t, dashboardStore, "TEST", orgId, 0, true, "prod")
|
folder := insertTestDashboard(t, dashboardStore, "TEST", orgId, 0, true, "prod")
|
||||||
dash := insertTestDashboard(t, dashboardStore, "Very Unique Name", orgId, folder.Id, false, "prod")
|
dash := insertTestDashboard(t, dashboardStore, "Very Unique Name", orgId, folder.Id, false, "prod")
|
||||||
|
|
||||||
@ -524,9 +512,7 @@ func TestIntegrationDashboardFolderDataAccess(t *testing.T) {
|
|||||||
t.Run("GetFolderByID", func(t *testing.T) {
|
t.Run("GetFolderByID", func(t *testing.T) {
|
||||||
var orgId int64 = 1
|
var orgId int64 = 1
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
folder := insertTestDashboard(t, dashboardStore, "TEST", orgId, 0, true, "prod")
|
folder := insertTestDashboard(t, dashboardStore, "TEST", orgId, 0, true, "prod")
|
||||||
dash := insertTestDashboard(t, dashboardStore, "Very Unique Name", orgId, folder.Id, false, "prod")
|
dash := insertTestDashboard(t, dashboardStore, "Very Unique Name", orgId, folder.Id, false, "prod")
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,9 +18,7 @@ func TestIntegrationDashboardProvisioningTest(t *testing.T) {
|
|||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, sqlStore.Cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
folderCmd := models.SaveDashboardCommand{
|
folderCmd := models.SaveDashboardCommand{
|
||||||
OrgId: 1,
|
OrgId: 1,
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
publicDashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
publicDashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||||
"github.com/grafana/grafana/pkg/services/star"
|
"github.com/grafana/grafana/pkg/services/star"
|
||||||
@ -43,10 +42,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
|
|||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
starService = starimpl.ProvideService(sqlStore, cfg)
|
starService = starimpl.ProvideService(sqlStore, cfg)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = ProvideDashboardStore(sqlStore, cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg))
|
||||||
var err error
|
|
||||||
dashboardStore, err = ProvideDashboardStore(sqlStore, cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
savedFolder = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
|
savedFolder = insertTestDashboard(t, dashboardStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
|
||||||
savedDash = insertTestDashboard(t, dashboardStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
|
savedDash = insertTestDashboard(t, dashboardStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
|
||||||
insertTestDashboard(t, dashboardStore, "test dash 45", 1, savedFolder.Id, false, "prod")
|
insertTestDashboard(t, dashboardStore, "test dash 45", 1, savedFolder.Id, false, "prod")
|
||||||
@ -589,9 +585,7 @@ func TestIntegrationDashboardDataAccessGivenPluginWithImportedDashboards(t *test
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, &setting.Cfg{}, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, &setting.Cfg{}, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
pluginId := "test-app"
|
pluginId := "test-app"
|
||||||
|
|
||||||
appFolder := insertTestDashboardForPlugin(t, dashboardStore, "app-test", 1, 0, true, pluginId)
|
appFolder := insertTestDashboardForPlugin(t, dashboardStore, "app-test", 1, 0, true, pluginId)
|
||||||
@ -603,7 +597,7 @@ func TestIntegrationDashboardDataAccessGivenPluginWithImportedDashboards(t *test
|
|||||||
OrgId: 1,
|
OrgId: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dashboardStore.GetDashboardsByPluginID(context.Background(), &query)
|
err := dashboardStore.GetDashboardsByPluginID(context.Background(), &query)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(query.Result), 2)
|
require.Equal(t, len(query.Result), 2)
|
||||||
}
|
}
|
||||||
@ -615,9 +609,7 @@ func TestIntegrationDashboard_SortingOptions(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, &setting.Cfg{}, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, &setting.Cfg{}, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
dashB := insertTestDashboard(t, dashboardStore, "Beta", 1, 0, false)
|
dashB := insertTestDashboard(t, dashboardStore, "Beta", 1, 0, false)
|
||||||
dashA := insertTestDashboard(t, dashboardStore, "Alfa", 1, 0, false)
|
dashA := insertTestDashboard(t, dashboardStore, "Alfa", 1, 0, false)
|
||||||
@ -668,9 +660,7 @@ func TestIntegrationDashboard_Filter(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
cfg.IsFeatureToggleEnabled = func(key string) bool { return false }
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := ProvideDashboardStore(sqlStore, cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := ProvideDashboardStore(sqlStore, cfg, testFeatureToggles, tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
insertTestDashboard(t, dashboardStore, "Alfa", 1, 0, false)
|
insertTestDashboard(t, dashboardStore, "Alfa", 1, 0, false)
|
||||||
dashB := insertTestDashboard(t, dashboardStore, "Beta", 1, 0, false)
|
dashB := insertTestDashboard(t, dashboardStore, "Beta", 1, 0, false)
|
||||||
qNoFilter := &models.FindPersistedDashboardsQuery{
|
qNoFilter := &models.FindPersistedDashboardsQuery{
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,11 +30,6 @@ type DashboardSearchProjection struct {
|
|||||||
SortMeta int64
|
SortMeta int64
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv quota.TargetSrv = "dashboard"
|
|
||||||
QuotaTarget quota.Target = "dashboard"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CountDashboardsInFolderQuery struct {
|
type CountDashboardsInFolderQuery struct {
|
||||||
FolderUID string
|
FolderUID string
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -43,7 +42,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardNotFound, err)
|
assert.Equal(t, dashboards.ErrDashboardNotFound, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: false,
|
Overwrite: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardNotFound, err)
|
assert.Equal(t, dashboards.ErrDashboardNotFound, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -105,7 +104,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sqlStore)
|
err := callSaveWithError(cmd, sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, int64(0), sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, int64(0), sc.dashboardGuardianMock.DashId)
|
||||||
@ -125,7 +124,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.otherSavedFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.otherSavedFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -145,7 +144,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -166,7 +165,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -187,7 +186,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -208,7 +207,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -229,7 +228,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -250,7 +249,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
assert.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -271,7 +270,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -292,7 +291,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: true,
|
Overwrite: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
require.Equal(t, dashboards.ErrDashboardUpdateAccessDenied, err)
|
||||||
|
|
||||||
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
||||||
@ -433,7 +432,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardFolderNotFound, err)
|
assert.Equal(t, dashboards.ErrDashboardFolderNotFound, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -449,7 +448,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err)
|
assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -489,7 +488,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err)
|
assert.Equal(t, dashboards.ErrDashboardVersionMismatch, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -528,7 +527,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
|
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -544,7 +543,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
|
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -560,7 +559,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
|
assert.Equal(t, dashboards.ErrDashboardWithSameNameInFolderExists, err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -648,7 +647,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardWithSameUIDExists, err)
|
assert.Equal(t, dashboards.ErrDashboardWithSameUIDExists, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -712,7 +711,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -728,7 +727,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -744,7 +743,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -760,7 +759,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
assert.Equal(t, dashboards.ErrDashboardTypeMismatch, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -775,7 +774,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardWithSameNameAsFolder, err)
|
assert.Equal(t, dashboards.ErrDashboardWithSameNameAsFolder, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -790,7 +789,7 @@ func TestIntegrationIntegratedDashboardService(t *testing.T) {
|
|||||||
Overwrite: shouldOverwrite,
|
Overwrite: shouldOverwrite,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := callSaveWithError(t, cmd, sc.sqlStore)
|
err := callSaveWithError(cmd, sc.sqlStore)
|
||||||
assert.Equal(t, dashboards.ErrDashboardFolderWithSameNameAsDashboard, err)
|
assert.Equal(t, dashboards.ErrDashboardFolderWithSameNameAsDashboard, err)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -822,9 +821,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
|
|||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
service := ProvideDashboardService(
|
service := ProvideDashboardService(
|
||||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||||
featuremgmt.WithFeatures(),
|
featuremgmt.WithFeatures(),
|
||||||
@ -881,9 +878,7 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore
|
|||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
service := ProvideDashboardService(
|
service := ProvideDashboardService(
|
||||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||||
featuremgmt.WithFeatures(),
|
featuremgmt.WithFeatures(),
|
||||||
@ -897,14 +892,12 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func callSaveWithError(t *testing.T, cmd models.SaveDashboardCommand, sqlStore db.DB) error {
|
func callSaveWithError(cmd models.SaveDashboardCommand, sqlStore db.DB) error {
|
||||||
dto := toSaveDashboardDto(cmd)
|
dto := toSaveDashboardDto(cmd)
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
service := ProvideDashboardService(
|
service := ProvideDashboardService(
|
||||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||||
featuremgmt.WithFeatures(),
|
featuremgmt.WithFeatures(),
|
||||||
@ -912,7 +905,7 @@ func callSaveWithError(t *testing.T, cmd models.SaveDashboardCommand, sqlStore d
|
|||||||
accesscontrolmock.NewMockedPermissionsService(),
|
accesscontrolmock.NewMockedPermissionsService(),
|
||||||
accesscontrolmock.New(),
|
accesscontrolmock.New(),
|
||||||
)
|
)
|
||||||
_, err = service.SaveDashboard(context.Background(), &dto, false)
|
_, err := service.SaveDashboard(context.Background(), &dto, false)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,9 +934,7 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
|
|||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
service := ProvideDashboardService(
|
service := ProvideDashboardService(
|
||||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||||
featuremgmt.WithFeatures(),
|
featuremgmt.WithFeatures(),
|
||||||
@ -981,9 +972,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *mo
|
|||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
service := ProvideDashboardService(
|
service := ProvideDashboardService(
|
||||||
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
cfg, dashboardStore, &dummyDashAlertExtractor{},
|
||||||
featuremgmt.WithFeatures(),
|
featuremgmt.WithFeatures(),
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
models "github.com/grafana/grafana/pkg/models"
|
models "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -474,10 +473,6 @@ type mockConstructorTestingTNewFakeDashboardStore interface {
|
|||||||
Cleanup(func())
|
Cleanup(func())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_m *FakeDashboardStore) Count(context.Context, *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
func NewFakeDashboardStore(t mockConstructorTestingTNewFakeDashboardStore) *FakeDashboardStore {
|
func NewFakeDashboardStore(t mockConstructorTestingTNewFakeDashboardStore) *FakeDashboardStore {
|
||||||
mock := &FakeDashboardStore{}
|
mock := &FakeDashboardStore{}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -194,8 +193,3 @@ type DatasourcesPermissionFilterQuery struct {
|
|||||||
Datasources []*DataSource
|
Datasources []*DataSource
|
||||||
Result []*DataSource
|
Result []*DataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv quota.TargetSrv = "data_source"
|
|
||||||
QuotaTarget quota.Target = "data_source"
|
|
||||||
)
|
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets"
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -53,8 +52,7 @@ type cachedRoundTripper struct {
|
|||||||
func ProvideService(
|
func ProvideService(
|
||||||
db db.DB, secretsService secrets.Service, secretsStore kvstore.SecretsKVStore, cfg *setting.Cfg,
|
db db.DB, secretsService secrets.Service, secretsStore kvstore.SecretsKVStore, cfg *setting.Cfg,
|
||||||
features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl, datasourcePermissionsService accesscontrol.DatasourcePermissionsService,
|
features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl, datasourcePermissionsService accesscontrol.DatasourcePermissionsService,
|
||||||
quotaService quota.Service,
|
) *Service {
|
||||||
) (*Service, error) {
|
|
||||||
dslogger := log.New("datasources")
|
dslogger := log.New("datasources")
|
||||||
store := &SqlStore{db: db, logger: dslogger}
|
store := &SqlStore{db: db, logger: dslogger}
|
||||||
s := &Service{
|
s := &Service{
|
||||||
@ -75,23 +73,7 @@ func ProvideService(
|
|||||||
ac.RegisterScopeAttributeResolver(NewNameScopeResolver(store))
|
ac.RegisterScopeAttributeResolver(NewNameScopeResolver(store))
|
||||||
ac.RegisterScopeAttributeResolver(NewIDScopeResolver(store))
|
ac.RegisterScopeAttributeResolver(NewIDScopeResolver(store))
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
return s
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: datasources.QuotaTargetSrv,
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.Usage,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Usage(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
return s.SQLStore.Count(ctx, scopeParams)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataSourceRetriever interface for retrieving a datasource.
|
// DataSourceRetriever interface for retrieving a datasource.
|
||||||
@ -609,24 +591,3 @@ func (s *Service) fillWithSecureJSONData(ctx context.Context, cmd *datasources.U
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(datasources.QuotaTargetSrv, datasources.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
orgQuotaTag, err := quota.NewTag(datasources.QuotaTargetSrv, datasources.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.DataSource)
|
|
||||||
limits.Set(orgQuotaTag, cfg.Quota.Org.DataSource)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets"
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
@ -201,9 +200,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
rt1, err := dsService.GetHTTPTransport(context.Background(), &ds, provider)
|
rt1, err := dsService.GetHTTPTransport(context.Background(), &ds, provider)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -238,9 +235,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
@ -289,9 +284,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
@ -337,9 +330,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
@ -382,9 +373,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
@ -417,9 +406,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
@ -486,9 +473,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Url: "http://k8s:8001",
|
Url: "http://k8s:8001",
|
||||||
@ -522,9 +507,7 @@ func TestService_GetHttpTransport(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
ds := datasources.DataSource{
|
ds := datasources.DataSource{
|
||||||
Type: datasources.DS_ES,
|
Type: datasources.DS_ES,
|
||||||
@ -561,9 +544,7 @@ func TestService_getTimeout(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
ds := &datasources.DataSource{
|
ds := &datasources.DataSource{
|
||||||
@ -584,9 +565,7 @@ func TestService_GetDecryptedValues(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, nil, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, nil, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
jsonData := map[string]string{
|
jsonData := map[string]string{
|
||||||
"password": "securePassword",
|
"password": "securePassword",
|
||||||
@ -612,9 +591,7 @@ func TestService_GetDecryptedValues(t *testing.T) {
|
|||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := ProvideService(sqlStore, secretsService, secretsStore, nil, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := ProvideService(sqlStore, secretsService, secretsStore, nil, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
jsonData := map[string]string{
|
jsonData := map[string]string{
|
||||||
"password": "securePassword",
|
"password": "securePassword",
|
||||||
|
@ -16,8 +16,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,8 +29,6 @@ type Store interface {
|
|||||||
AddDataSource(context.Context, *datasources.AddDataSourceCommand) error
|
AddDataSource(context.Context, *datasources.AddDataSourceCommand) error
|
||||||
UpdateDataSource(context.Context, *datasources.UpdateDataSourceCommand) error
|
UpdateDataSource(context.Context, *datasources.UpdateDataSourceCommand) error
|
||||||
GetAllDataSources(ctx context.Context, query *datasources.GetAllDataSourcesQuery) error
|
GetAllDataSources(ctx context.Context, query *datasources.GetAllDataSourcesQuery) error
|
||||||
|
|
||||||
Count(context.Context, *quota.ScopeParameters) (*quota.Map, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SqlStore struct {
|
type SqlStore struct {
|
||||||
@ -175,50 +171,6 @@ func (ss *SqlStore) DeleteDataSource(ctx context.Context, cmd *datasources.Delet
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SqlStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := "SELECT COUNT(*) AS count FROM data_source"
|
|
||||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(datasources.QuotaTargetSrv, datasources.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.OrgID != 0 {
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := "SELECT COUNT(*) AS count FROM data_source WHERE org_id=?"
|
|
||||||
if _, err := sess.SQL(rawSQL, scopeParams.OrgID).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(datasources.QuotaTargetSrv, datasources.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *SqlStore) AddDataSource(ctx context.Context, cmd *datasources.AddDataSourceCommand) error {
|
func (ss *SqlStore) AddDataSource(ctx context.Context, cmd *datasources.AddDataSourceCommand) error {
|
||||||
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
|
||||||
existing := datasources.DataSource{OrgId: cmd.OrgId, Name: cmd.Name}
|
existing := datasources.DataSource{OrgId: cmd.OrgId, Name: cmd.Name}
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/folder"
|
"github.com/grafana/grafana/pkg/services/folder"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -584,8 +583,7 @@ func TestIntegrationGetChildren(t *testing.T) {
|
|||||||
func CreateOrg(t *testing.T, db *sqlstore.SQLStore) int64 {
|
func CreateOrg(t *testing.T, db *sqlstore.SQLStore) int64 {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
orgService, err := orgimpl.ProvideService(db, db.Cfg, quotatest.New(false, nil))
|
orgService := orgimpl.ProvideService(db, db.Cfg)
|
||||||
require.NoError(t, err)
|
|
||||||
orgID, err := orgService.GetOrCreate(context.Background(), "test-org")
|
orgID, err := orgService.GetOrCreate(context.Background(), "test-org")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -19,7 +19,6 @@ import (
|
|||||||
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
dashdb "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -592,9 +591,7 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
|
|||||||
toSave.SetUid(uid)
|
toSave.SetUid(uid)
|
||||||
|
|
||||||
// seed dashboard
|
// seed dashboard
|
||||||
quotaService := quotatest.New(false, nil)
|
dashStore := dashdb.ProvideDashboardStore(store, store.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(store, store.Cfg))
|
||||||
dashStore, err := dashdb.ProvideDashboardStore(store, store.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(store, store.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dash, err := dashStore.SaveDashboard(context.Background(), models.SaveDashboardCommand{
|
dash, err := dashStore.SaveDashboard(context.Background(), models.SaveDashboardCommand{
|
||||||
Dashboard: toSave.Data,
|
Dashboard: toSave.Data,
|
||||||
UserId: 1,
|
UserId: 1,
|
||||||
@ -606,8 +603,7 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
|
|||||||
license := licensingtest.NewFakeLicensing()
|
license := licensingtest.NewFakeLicensing()
|
||||||
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
|
||||||
teamSvc := teamimpl.ProvideService(store, store.Cfg)
|
teamSvc := teamimpl.ProvideService(store, store.Cfg)
|
||||||
userSvc, err := userimpl.ProvideService(store, nil, store.Cfg, nil, nil, quotatest.New(false, nil))
|
userSvc := userimpl.ProvideService(store, nil, store.Cfg, nil, nil)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
|
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
|
||||||
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, ac, teamSvc, userSvc)
|
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, ac, teamSvc, userSvc)
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -279,9 +278,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
|
|||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
cfg.IsFeatureToggleEnabled = features.IsEnabled
|
cfg.IsFeatureToggleEnabled = features.IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashAlertExtractor := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
|
dashAlertExtractor := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
|
||||||
ac := acmock.New()
|
ac := acmock.New()
|
||||||
folderPermissions := acmock.NewMockedPermissionsService()
|
folderPermissions := acmock.NewMockedPermissionsService()
|
||||||
@ -307,9 +304,7 @@ func createFolderWithACL(t *testing.T, sqlStore db.DB, title string, user user.S
|
|||||||
ac := acmock.New()
|
ac := acmock.New()
|
||||||
folderPermissions := acmock.NewMockedPermissionsService()
|
folderPermissions := acmock.NewMockedPermissionsService()
|
||||||
dashboardPermissions := acmock.NewMockedPermissionsService()
|
dashboardPermissions := acmock.NewMockedPermissionsService()
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
d := dashboardservice.ProvideDashboardService(
|
d := dashboardservice.ProvideDashboardService(
|
||||||
cfg, dashboardStore, nil,
|
cfg, dashboardStore, nil,
|
||||||
@ -410,9 +405,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
orgID := int64(1)
|
orgID := int64(1)
|
||||||
role := org.RoleAdmin
|
role := org.RoleAdmin
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
ac := acmock.New().WithDisabled()
|
ac := acmock.New().WithDisabled()
|
||||||
// TODO: Update tests to work with rbac
|
// TODO: Update tests to work with rbac
|
||||||
@ -449,7 +442,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
Login: userInDbName,
|
Login: userInDbName,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sqlStore.CreateUser(context.Background(), cmd)
|
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sc := scenarioContext{
|
sc := scenarioContext{
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
"github.com/grafana/grafana/pkg/services/libraryelements"
|
"github.com/grafana/grafana/pkg/services/libraryelements"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
"github.com/grafana/grafana/pkg/services/team/teamtest"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -692,9 +691,7 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash
|
|||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
cfg.RBACEnabled = false
|
cfg.RBACEnabled = false
|
||||||
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
cfg.IsFeatureToggleEnabled = featuremgmt.WithFeatures().IsEnabled
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
|
dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
|
||||||
ac := acmock.New()
|
ac := acmock.New()
|
||||||
service := dashboardservice.ProvideDashboardService(
|
service := dashboardservice.ProvideDashboardService(
|
||||||
@ -718,9 +715,7 @@ func createFolderWithACL(t *testing.T, sqlStore db.DB, title string, user *user.
|
|||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
folderPermissions := acmock.NewMockedPermissionsService()
|
folderPermissions := acmock.NewMockedPermissionsService()
|
||||||
dashboardPermissions := acmock.NewMockedPermissionsService()
|
dashboardPermissions := acmock.NewMockedPermissionsService()
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac)
|
d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac)
|
||||||
s := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, d, dashboardStore, features, folderPermissions, nil)
|
s := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, d, dashboardStore, features, folderPermissions, nil)
|
||||||
|
|
||||||
@ -813,9 +808,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
orgID := int64(1)
|
orgID := int64(1)
|
||||||
role := org.RoleAdmin
|
role := org.RoleAdmin
|
||||||
sqlStore, cfg := db.InitTestDBwithCfg(t)
|
sqlStore, cfg := db.InitTestDBwithCfg(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
ac := acmock.New()
|
ac := acmock.New()
|
||||||
@ -854,7 +847,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
|
|||||||
Login: userInDbName,
|
Login: userInDbName,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sqlStore.CreateUser(context.Background(), cmd)
|
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sc := scenarioContext{
|
sc := scenarioContext{
|
||||||
|
@ -71,10 +71,7 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser
|
|||||||
return login.ErrSignupNotAllowed
|
return login.ErrSignupNotAllowed
|
||||||
}
|
}
|
||||||
|
|
||||||
// we may insert in both user and org_user tables
|
limitReached, errLimit := ls.QuotaService.QuotaReached(cmd.ReqContext, "user")
|
||||||
// therefore we need to query check quota for both user and org services
|
|
||||||
for _, srv := range []string{user.QuotaTargetSrv, org.QuotaTargetSrv} {
|
|
||||||
limitReached, errLimit := ls.QuotaService.QuotaReached(cmd.ReqContext, quota.TargetSrv(srv))
|
|
||||||
if errLimit != nil {
|
if errLimit != nil {
|
||||||
cmd.ReqContext.Logger.Warn("Error getting user quota.", "error", errLimit)
|
cmd.ReqContext.Logger.Warn("Error getting user quota.", "error", errLimit)
|
||||||
return login.ErrGettingUserQuota
|
return login.ErrGettingUserQuota
|
||||||
@ -82,7 +79,6 @@ func (ls *Implementation) UpsertUser(ctx context.Context, cmd *models.UpsertUser
|
|||||||
if limitReached {
|
if limitReached {
|
||||||
return login.ErrUsersQuotaReached
|
return login.ErrUsersQuotaReached
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
result, errCreateUser := ls.createUser(extUser)
|
result, errCreateUser := ls.createUser(extUser)
|
||||||
if errCreateUser != nil {
|
if errCreateUser != nil {
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/login/logintest"
|
"github.com/grafana/grafana/pkg/services/login/logintest"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
"github.com/grafana/grafana/pkg/services/org/orgtest"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/services/user/usertest"
|
"github.com/grafana/grafana/pkg/services/user/usertest"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -26,7 +26,7 @@ func Test_syncOrgRoles_doesNotBreakWhenTryingToRemoveLastOrgAdmin(t *testing.T)
|
|||||||
authInfoMock := &logintest.AuthInfoServiceFake{}
|
authInfoMock := &logintest.AuthInfoServiceFake{}
|
||||||
|
|
||||||
login := Implementation{
|
login := Implementation{
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{},
|
||||||
AuthInfoService: authInfoMock,
|
AuthInfoService: authInfoMock,
|
||||||
SQLStore: nil,
|
SQLStore: nil,
|
||||||
userService: usertest.NewUserServiceFake(),
|
userService: usertest.NewUserServiceFake(),
|
||||||
@ -51,7 +51,7 @@ func Test_syncOrgRoles_whenTryingToRemoveLastOrgLogsError(t *testing.T) {
|
|||||||
orgService.ExpectedOrgListResponse = createResponseWithOneErrLastOrgAdminItem()
|
orgService.ExpectedOrgListResponse = createResponseWithOneErrLastOrgAdminItem()
|
||||||
|
|
||||||
login := Implementation{
|
login := Implementation{
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{},
|
||||||
AuthInfoService: authInfoMock,
|
AuthInfoService: authInfoMock,
|
||||||
SQLStore: nil,
|
SQLStore: nil,
|
||||||
userService: usertest.NewUserServiceFake(),
|
userService: usertest.NewUserServiceFake(),
|
||||||
@ -66,7 +66,7 @@ func Test_syncOrgRoles_whenTryingToRemoveLastOrgLogsError(t *testing.T) {
|
|||||||
func Test_teamSync(t *testing.T) {
|
func Test_teamSync(t *testing.T) {
|
||||||
authInfoMock := &logintest.AuthInfoServiceFake{}
|
authInfoMock := &logintest.AuthInfoServiceFake{}
|
||||||
login := Implementation{
|
login := Implementation{
|
||||||
QuotaService: quotatest.New(false, nil),
|
QuotaService: "aimpl.Service{},
|
||||||
AuthInfoService: authInfoMock,
|
AuthInfoService: authInfoMock,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,28 +145,3 @@ func (api *API) RegisterAPIEndpoints(m *metrics.API) {
|
|||||||
alertRules: api.AlertRules,
|
alertRules: api.AlertRules,
|
||||||
}), m)
|
}), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) Usage(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
if orgUsage, err := api.RuleStore.Count(ctx, scopeParams.OrgID); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(models.QuotaTargetSrv, models.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, orgUsage)
|
|
||||||
}
|
|
||||||
|
|
||||||
if globalUsage, err := api.RuleStore.Count(ctx, 0); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(models.QuotaTargetSrv, models.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, globalUsage)
|
|
||||||
}
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
@ -393,7 +393,7 @@ func (srv RulerSrv) updateAlertRulesInGroup(c *models.ReqContext, groupKey ngmod
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(finalChanges.New) > 0 {
|
if len(finalChanges.New) > 0 {
|
||||||
limitReached, err := srv.QuotaService.CheckQuotaReached(tranCtx, ngmodels.QuotaTargetSrv, "a.ScopeParameters{
|
limitReached, err := srv.QuotaService.CheckQuotaReached(tranCtx, "alert_rule", "a.ScopeParameters{
|
||||||
OrgID: c.OrgID,
|
OrgID: c.OrgID,
|
||||||
UserID: c.UserID,
|
UserID: c.UserID,
|
||||||
}) // alert rule is table name
|
}) // alert rule is table name
|
||||||
|
@ -23,6 +23,4 @@ type RuleStore interface {
|
|||||||
|
|
||||||
// IncreaseVersionForAllRulesInNamespace Increases version for all rules that have specified namespace. Returns all rules that belong to the namespace
|
// IncreaseVersionForAllRulesInNamespace Increases version for all rules that have specified namespace. Returns all rules that belong to the namespace
|
||||||
IncreaseVersionForAllRulesInNamespace(ctx context.Context, orgID int64, namespaceUID string) ([]ngmodels.AlertRuleKeyWithVersion, error)
|
IncreaseVersionForAllRulesInNamespace(ctx context.Context, orgID int64, namespaceUID string) ([]ngmodels.AlertRuleKeyWithVersion, error)
|
||||||
|
|
||||||
Count(ctx context.Context, orgID int64) (int64, error)
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/util/cmputil"
|
"github.com/grafana/grafana/pkg/util/cmputil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -461,11 +460,6 @@ func (g RulesGroup) SortByGroupIndex() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv quota.TargetSrv = "ngalert"
|
|
||||||
QuotaTarget quota.Target = "alert_rule"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ruleKeyContextKey struct{}
|
type ruleKeyContextKey struct{}
|
||||||
|
|
||||||
func WithRuleKey(ctx context.Context, ruleKey AlertRuleKey) context.Context {
|
func WithRuleKey(ctx context.Context, ruleKey AlertRuleKey) context.Context {
|
||||||
|
@ -239,19 +239,6 @@ func (ng *AlertNG) init() error {
|
|||||||
}
|
}
|
||||||
api.RegisterAPIEndpoints(ng.Metrics.GetAPIMetrics())
|
api.RegisterAPIEndpoints(ng.Metrics.GetAPIMetrics())
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(ng.Cfg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ng.QuotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: models.QuotaTargetSrv,
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: api.Usage,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.RegisterContextualLogProvider(func(ctx context.Context) ([]interface{}, bool) {
|
log.RegisterContextualLogProvider(func(ctx context.Context) ([]interface{}, bool) {
|
||||||
key, ok := models.RuleKeyFromContext(ctx)
|
key, ok := models.RuleKeyFromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -321,32 +308,3 @@ func (ng *AlertNG) IsDisabled() bool {
|
|||||||
}
|
}
|
||||||
return !ng.Cfg.UnifiedAlerting.IsEnabled()
|
return !ng.Cfg.UnifiedAlerting.IsEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var alertOrgQuota int64
|
|
||||||
var alertGlobalQuota int64
|
|
||||||
|
|
||||||
if cfg.UnifiedAlerting.IsEnabled() {
|
|
||||||
alertOrgQuota = cfg.Quota.Org.AlertRule
|
|
||||||
alertGlobalQuota = cfg.Quota.Global.AlertRule
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(models.QuotaTargetSrv, models.QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
orgQuotaTag, err := quota.NewTag(models.QuotaTargetSrv, models.QuotaTarget, quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, alertGlobalQuota)
|
|
||||||
limits.Set(orgQuotaTag, alertOrgQuota)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
@ -48,7 +48,7 @@ type RuleStore interface {
|
|||||||
//
|
//
|
||||||
//go:generate mockery --name QuotaChecker --structname MockQuotaChecker --inpackage --filename quota_checker_mock.go --with-expecter
|
//go:generate mockery --name QuotaChecker --structname MockQuotaChecker --inpackage --filename quota_checker_mock.go --with-expecter
|
||||||
type QuotaChecker interface {
|
type QuotaChecker interface {
|
||||||
CheckQuotaReached(ctx context.Context, target quota.TargetSrv, scopeParams *quota.ScopeParameters) (bool, error)
|
CheckQuotaReached(ctx context.Context, target string, scopeParams *quota.ScopeParameters) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersistConfig validates to config before eventually persisting it if no error occurs
|
// PersistConfig validates to config before eventually persisting it if no error occurs
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
// Code generated by mockery v2.12.0. DO NOT EDIT.
|
||||||
|
|
||||||
package provisioning
|
package provisioning
|
||||||
|
|
||||||
@ -7,6 +7,8 @@ import (
|
|||||||
|
|
||||||
quota "github.com/grafana/grafana/pkg/services/quota"
|
quota "github.com/grafana/grafana/pkg/services/quota"
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
testing "testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockQuotaChecker is an autogenerated mock type for the QuotaChecker type
|
// MockQuotaChecker is an autogenerated mock type for the QuotaChecker type
|
||||||
@ -23,18 +25,18 @@ func (_m *MockQuotaChecker) EXPECT() *MockQuotaChecker_Expecter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CheckQuotaReached provides a mock function with given fields: ctx, target, scopeParams
|
// CheckQuotaReached provides a mock function with given fields: ctx, target, scopeParams
|
||||||
func (_m *MockQuotaChecker) CheckQuotaReached(ctx context.Context, target quota.TargetSrv, scopeParams *quota.ScopeParameters) (bool, error) {
|
func (_m *MockQuotaChecker) CheckQuotaReached(ctx context.Context, target string, scopeParams *quota.ScopeParameters) (bool, error) {
|
||||||
ret := _m.Called(ctx, target, scopeParams)
|
ret := _m.Called(ctx, target, scopeParams)
|
||||||
|
|
||||||
var r0 bool
|
var r0 bool
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, quota.TargetSrv, *quota.ScopeParameters) bool); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string, *quota.ScopeParameters) bool); ok {
|
||||||
r0 = rf(ctx, target, scopeParams)
|
r0 = rf(ctx, target, scopeParams)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Get(0).(bool)
|
r0 = ret.Get(0).(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, quota.TargetSrv, *quota.ScopeParameters) error); ok {
|
if rf, ok := ret.Get(1).(func(context.Context, string, *quota.ScopeParameters) error); ok {
|
||||||
r1 = rf(ctx, target, scopeParams)
|
r1 = rf(ctx, target, scopeParams)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
@ -50,15 +52,15 @@ type MockQuotaChecker_CheckQuotaReached_Call struct {
|
|||||||
|
|
||||||
// CheckQuotaReached is a helper method to define mock.On call
|
// CheckQuotaReached is a helper method to define mock.On call
|
||||||
// - ctx context.Context
|
// - ctx context.Context
|
||||||
// - target quota.TargetSrv
|
// - target string
|
||||||
// - scopeParams *quota.ScopeParameters
|
// - scopeParams *quota.ScopeParameters
|
||||||
func (_e *MockQuotaChecker_Expecter) CheckQuotaReached(ctx interface{}, target interface{}, scopeParams interface{}) *MockQuotaChecker_CheckQuotaReached_Call {
|
func (_e *MockQuotaChecker_Expecter) CheckQuotaReached(ctx interface{}, target interface{}, scopeParams interface{}) *MockQuotaChecker_CheckQuotaReached_Call {
|
||||||
return &MockQuotaChecker_CheckQuotaReached_Call{Call: _e.mock.On("CheckQuotaReached", ctx, target, scopeParams)}
|
return &MockQuotaChecker_CheckQuotaReached_Call{Call: _e.mock.On("CheckQuotaReached", ctx, target, scopeParams)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_c *MockQuotaChecker_CheckQuotaReached_Call) Run(run func(ctx context.Context, target quota.TargetSrv, scopeParams *quota.ScopeParameters)) *MockQuotaChecker_CheckQuotaReached_Call {
|
func (_c *MockQuotaChecker_CheckQuotaReached_Call) Run(run func(ctx context.Context, target string, scopeParams *quota.ScopeParameters)) *MockQuotaChecker_CheckQuotaReached_Call {
|
||||||
_c.Call.Run(func(args mock.Arguments) {
|
_c.Call.Run(func(args mock.Arguments) {
|
||||||
run(args[0].(context.Context), args[1].(quota.TargetSrv), args[2].(*quota.ScopeParameters))
|
run(args[0].(context.Context), args[1].(string), args[2].(*quota.ScopeParameters))
|
||||||
})
|
})
|
||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
@ -68,13 +70,8 @@ func (_c *MockQuotaChecker_CheckQuotaReached_Call) Return(_a0 bool, _a1 error) *
|
|||||||
return _c
|
return _c
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockConstructorTestingTNewMockQuotaChecker interface {
|
// NewMockQuotaChecker creates a new instance of MockQuotaChecker. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
|
||||||
mock.TestingT
|
func NewMockQuotaChecker(t testing.TB) *MockQuotaChecker {
|
||||||
Cleanup(func())
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockQuotaChecker creates a new instance of MockQuotaChecker. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
|
||||||
func NewMockQuotaChecker(t mockConstructorTestingTNewMockQuotaChecker) *MockQuotaChecker {
|
|
||||||
mock := &MockQuotaChecker{}
|
mock := &MockQuotaChecker{}
|
||||||
mock.Mock.Test(t)
|
mock.Mock.Test(t)
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/guardian"
|
"github.com/grafana/grafana/pkg/services/guardian"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
@ -269,29 +268,6 @@ func (st DBstore) ListAlertRules(ctx context.Context, query *ngmodels.ListAlertR
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count returns either the number of the alert rules under a specific org (if orgID is not zero)
|
|
||||||
// or the number of all the alert rules
|
|
||||||
func (st DBstore) Count(ctx context.Context, orgID int64) (int64, error) {
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
err := st.SQLStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := "SELECT COUNT(*) as count from alert_rule"
|
|
||||||
args := make([]interface{}, 0)
|
|
||||||
if orgID != 0 {
|
|
||||||
rawSQL += " WHERE org_id=?"
|
|
||||||
args = append(args, orgID)
|
|
||||||
}
|
|
||||||
if _, err := sess.SQL(rawSQL, args...).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return r.Count, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st DBstore) GetRuleGroupInterval(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string) (int64, error) {
|
func (st DBstore) GetRuleGroupInterval(ctx context.Context, orgID int64, namespaceUID string, ruleGroup string) (int64, error) {
|
||||||
var interval int64 = 0
|
var interval int64 = 0
|
||||||
return interval, st.SQLStore.WithDbSession(ctx, func(sess *db.Session) error {
|
return interval, st.SQLStore.WithDbSession(ctx, func(sess *db.Session) error {
|
||||||
|
@ -339,7 +339,3 @@ func (f *RuleStore) IncreaseVersionForAllRulesInNamespace(_ context.Context, org
|
|||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *RuleStore) Count(ctx context.Context, orgID int64) (int64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
@ -31,7 +31,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
@ -76,9 +75,7 @@ func SetupTestEnv(tb testing.TB, baseInterval time.Duration) (*ngalert.AlertNG,
|
|||||||
m := metrics.NewNGAlert(prometheus.NewRegistry())
|
m := metrics.NewNGAlert(prometheus.NewRegistry())
|
||||||
sqlStore := db.InitTestDB(tb)
|
sqlStore := db.InitTestDB(tb)
|
||||||
secretsService := secretsManager.SetupTestService(tb, database.ProvideSecretsStore(sqlStore))
|
secretsService := secretsManager.SetupTestService(tb, database.ProvideSecretsStore(sqlStore))
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := databasestore.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := databasestore.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(tb, err)
|
|
||||||
|
|
||||||
ac := acmock.New()
|
ac := acmock.New()
|
||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
@ -95,7 +92,7 @@ func SetupTestEnv(tb testing.TB, baseInterval time.Duration) (*ngalert.AlertNG,
|
|||||||
folderService := folderimpl.ProvideService(ac, bus, cfg, dashboardService, dashboardStore, features, folderPermissions, nil)
|
folderService := folderimpl.ProvideService(ac, bus, cfg, dashboardService, dashboardStore, features, folderPermissions, nil)
|
||||||
|
|
||||||
ng, err := ngalert.ProvideService(
|
ng, err := ngalert.ProvideService(
|
||||||
cfg, &FakeFeatures{}, nil, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, quotatest.New(false, nil),
|
cfg, &FakeFeatures{}, nil, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, nil,
|
||||||
secretsService, nil, m, folderService, ac, &dashboards.FakeDashboardService{}, nil, bus, ac, annotationstest.NewFakeAnnotationsRepo(),
|
secretsService, nil, m, folderService, ac, &dashboards.FakeDashboardService{}, nil, bus, ac, annotationstest.NewFakeAnnotationsRepo(),
|
||||||
)
|
)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
@ -204,9 +204,3 @@ func (o ByOrgName) Less(i, j int) bool {
|
|||||||
|
|
||||||
return o[i].Name < o[j].Name
|
return o[i].Name < o[j].Name
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv string = "org"
|
|
||||||
OrgQuotaTarget string = "org"
|
|
||||||
OrgUserQuotaTarget string = "org_user"
|
|
||||||
)
|
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
@ -19,9 +18,9 @@ type Service struct {
|
|||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(db db.DB, cfg *setting.Cfg, quotaService quota.Service) (org.Service, error) {
|
func ProvideService(db db.DB, cfg *setting.Cfg) org.Service {
|
||||||
log := log.New("org service")
|
log := log.New("org service")
|
||||||
s := &Service{
|
return &Service{
|
||||||
store: &sqlStore{
|
store: &sqlStore{
|
||||||
db: db,
|
db: db,
|
||||||
dialect: db.GetDialect(),
|
dialect: db.GetDialect(),
|
||||||
@ -31,24 +30,6 @@ func ProvideService(db db.DB, cfg *setting.Cfg, quotaService quota.Service) (org
|
|||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
log: log,
|
log: log,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: quota.TargetSrv(org.QuotaTargetSrv),
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.Usage,
|
|
||||||
}); err != nil {
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Usage(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
return s.store.Count(ctx, scopeParams)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetIDForNewUser(ctx context.Context, cmd org.GetOrgIDForNewUserCommand) (int64, error) {
|
func (s *Service) GetIDForNewUser(ctx context.Context, cmd org.GetOrgIDForNewUserCommand) (int64, error) {
|
||||||
@ -198,31 +179,3 @@ func (s *Service) GetOrgUsers(ctx context.Context, query *org.GetOrgUsersQuery)
|
|||||||
func (s *Service) SearchOrgUsers(ctx context.Context, query *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error) {
|
func (s *Service) SearchOrgUsers(ctx context.Context, query *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error) {
|
||||||
return s.store.SearchOrgUsers(ctx, query)
|
return s.store.SearchOrgUsers(ctx, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgQuotaTarget), quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
orgQuotaTag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
userTag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.UserScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.Org)
|
|
||||||
// users per org
|
|
||||||
limits.Set(orgQuotaTag, cfg.Quota.Org.User)
|
|
||||||
// orgs per user
|
|
||||||
limits.Set(userTag, cfg.Quota.User.Org)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@ -136,7 +135,3 @@ func (f *FakeOrgStore) SearchOrgUsers(ctx context.Context, query *org.SearchOrgU
|
|||||||
func (f *FakeOrgStore) RemoveOrgUser(ctx context.Context, cmd *org.RemoveOrgUserCommand) error {
|
func (f *FakeOrgStore) RemoveOrgUser(ctx context.Context, cmd *org.RemoveOrgUserCommand) error {
|
||||||
return f.ExpectedError
|
return f.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeOrgStore) Count(ctx context.Context, _ *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
@ -14,8 +14,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -44,8 +42,6 @@ type store interface {
|
|||||||
GetByName(context.Context, *org.GetOrgByNameQuery) (*org.Org, error)
|
GetByName(context.Context, *org.GetOrgByNameQuery) (*org.Org, error)
|
||||||
SearchOrgUsers(context.Context, *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error)
|
SearchOrgUsers(context.Context, *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error)
|
||||||
RemoveOrgUser(context.Context, *org.RemoveOrgUserCommand) error
|
RemoveOrgUser(context.Context, *org.RemoveOrgUserCommand) error
|
||||||
|
|
||||||
Count(context.Context, *quota.ScopeParameters) (*quota.Map, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sqlStore struct {
|
type sqlStore struct {
|
||||||
@ -399,72 +395,6 @@ func (ss *sqlStore) AddOrgUser(ctx context.Context, cmd *org.AddOrgUserCommand)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) Count(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := "SELECT COUNT(*) as count from org"
|
|
||||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgQuotaTarget), quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.OrgID != 0 {
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM (SELECT user_id FROM org_user WHERE org_id=? AND user_id IN (SELECT id AS user_id FROM %s WHERE is_service_account=%s)) as subq",
|
|
||||||
ss.db.GetDialect().Quote("user"),
|
|
||||||
ss.db.GetDialect().BooleanStr(false),
|
|
||||||
)
|
|
||||||
if _, err := sess.SQL(rawSQL, scopeParams.OrgID).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.UserID != 0 {
|
|
||||||
if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
// should we exclude service accounts?
|
|
||||||
rawSQL := "SELECT COUNT(*) AS count FROM org_user WHERE user_id=?"
|
|
||||||
if _, err := sess.SQL(rawSQL, scopeParams.UserID).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.UserScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return u, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setUsingOrgInTransaction(sess *db.Session, userID int64, orgID int64) error {
|
func setUsingOrgInTransaction(sess *db.Session, userID int64, orgID int64) error {
|
||||||
user := user.User{
|
user := user.User{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
publicdashboardsStore "github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
publicdashboardsStore "github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -301,8 +300,7 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create dashboard
|
// create dashboard
|
||||||
dashboardStoreService, err := dashboardStore.ProvideDashboardStore(db, db.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db, db.Cfg), quotatest.New(false, nil))
|
dashboardStoreService := dashboardStore.ProvideDashboardStore(db, db.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db, db.Cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
dashboard, err := dashboardStoreService.SaveDashboard(context.Background(), saveDashboardCmd)
|
dashboard, err := dashboardStoreService.SaveDashboard(context.Background(), saveDashboardCmd)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
@ -36,9 +35,7 @@ func TestIntegrationListPublicDashboard(t *testing.T) {
|
|||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
sqlStore, cfg := db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
sqlStore, cfg := db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := ProvideStore(sqlStore)
|
publicdashboardStore := ProvideStore(sqlStore)
|
||||||
|
|
||||||
var orgId int64 = 1
|
var orgId int64 = 1
|
||||||
@ -81,10 +78,7 @@ func TestIntegrationFindDashboard(t *testing.T) {
|
|||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashboardStore = store
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
@ -111,10 +105,7 @@ func TestIntegrationExistsEnabledByAccessToken(t *testing.T) {
|
|||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashboardStore = store
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
@ -184,10 +175,7 @@ func TestIntegrationExistsEnabledByDashboardUid(t *testing.T) {
|
|||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashboardStore = store
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
@ -249,10 +237,7 @@ func TestIntegrationFindByDashboardUid(t *testing.T) {
|
|||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashboardStore = store
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
@ -314,12 +299,10 @@ func TestIntegrationFindByAccessToken(t *testing.T) {
|
|||||||
var dashboardStore *dashboardsDB.DashboardStore
|
var dashboardStore *dashboardsDB.DashboardStore
|
||||||
var publicdashboardStore *PublicDashboardStoreImpl
|
var publicdashboardStore *PublicDashboardStoreImpl
|
||||||
var savedDashboard *models.Dashboard
|
var savedDashboard *models.Dashboard
|
||||||
var err error
|
|
||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
@ -386,10 +369,7 @@ func TestIntegrationCreatePublicDashboard(t *testing.T) {
|
|||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
sqlStore, cfg = db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
store, err := dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
dashboardStore = store
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, true)
|
savedDashboard2 = insertTestDashboard(t, dashboardStore, "testDashie2", 1, 0, true)
|
||||||
@ -456,13 +436,10 @@ func TestIntegrationUpdatePublicDashboard(t *testing.T) {
|
|||||||
var publicdashboardStore *PublicDashboardStoreImpl
|
var publicdashboardStore *PublicDashboardStoreImpl
|
||||||
var savedDashboard *models.Dashboard
|
var savedDashboard *models.Dashboard
|
||||||
var anotherSavedDashboard *models.Dashboard
|
var anotherSavedDashboard *models.Dashboard
|
||||||
var err error
|
|
||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
sqlStore, cfg = db.InitTestDBwithCfg(t, db.InitTestDBOpt{FeatureFlags: []string{featuremgmt.FlagPublicDashboards}})
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
anotherSavedDashboard = insertTestDashboard(t, dashboardStore, "test another Dashie", 1, 0, true)
|
anotherSavedDashboard = insertTestDashboard(t, dashboardStore, "test another Dashie", 1, 0, true)
|
||||||
@ -552,13 +529,10 @@ func TestIntegrationGetOrgIdByAccessToken(t *testing.T) {
|
|||||||
var dashboardStore *dashboardsDB.DashboardStore
|
var dashboardStore *dashboardsDB.DashboardStore
|
||||||
var publicdashboardStore *PublicDashboardStoreImpl
|
var publicdashboardStore *PublicDashboardStoreImpl
|
||||||
var savedDashboard *models.Dashboard
|
var savedDashboard *models.Dashboard
|
||||||
var err error
|
|
||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
}
|
}
|
||||||
@ -625,12 +599,10 @@ func TestIntegrationDelete(t *testing.T) {
|
|||||||
var publicdashboardStore *PublicDashboardStoreImpl
|
var publicdashboardStore *PublicDashboardStoreImpl
|
||||||
var savedDashboard *models.Dashboard
|
var savedDashboard *models.Dashboard
|
||||||
var savedPublicDashboard *PublicDashboard
|
var savedPublicDashboard *PublicDashboard
|
||||||
var err error
|
|
||||||
|
|
||||||
setup := func() {
|
setup := func() {
|
||||||
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
sqlStore, cfg = db.InitTestDBwithCfg(t)
|
||||||
dashboardStore, err = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotatest.New(false, nil))
|
dashboardStore = dashboardsDB.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore = ProvideStore(sqlStore)
|
publicdashboardStore = ProvideStore(sqlStore)
|
||||||
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
|
||||||
savedPublicDashboard = insertPublicDashboard(t, publicdashboardStore, savedDashboard.Uid, savedDashboard.OrgId, true)
|
savedPublicDashboard = insertPublicDashboard(t, publicdashboardStore, savedDashboard.Uid, savedDashboard.OrgId, true)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/internal"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -356,8 +355,7 @@ const (
|
|||||||
|
|
||||||
func TestGetQueryDataResponse(t *testing.T) {
|
func TestGetQueryDataResponse(t *testing.T) {
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
sqlStore := sqlstore.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
|
|
||||||
service := &PublicDashboardServiceImpl{
|
service := &PublicDashboardServiceImpl{
|
||||||
@ -740,8 +738,7 @@ func TestGetAnnotations(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetMetricRequest(t *testing.T) {
|
func TestGetMetricRequest(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
publicDashboard := &PublicDashboard{
|
publicDashboard := &PublicDashboard{
|
||||||
@ -814,8 +811,7 @@ func TestGetUniqueDashboardDatasourceUids(t *testing.T) {
|
|||||||
|
|
||||||
func TestBuildMetricRequest(t *testing.T) {
|
func TestBuildMetricRequest(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
|
|
||||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
@ -1026,8 +1022,7 @@ func TestBuildMetricRequest(t *testing.T) {
|
|||||||
|
|
||||||
func TestBuildAnonymousUser(t *testing.T) {
|
func TestBuildAnonymousUser(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
//publicdashboardStore := database.ProvideStore(sqlStore)
|
//publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
//service := &PublicDashboardServiceImpl{
|
//service := &PublicDashboardServiceImpl{
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -126,9 +125,7 @@ func TestGetPublicDashboard(t *testing.T) {
|
|||||||
func TestCreatePublicDashboard(t *testing.T) {
|
func TestCreatePublicDashboard(t *testing.T) {
|
||||||
t.Run("Create public dashboard", func(t *testing.T) {
|
t.Run("Create public dashboard", func(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
|
|
||||||
@ -150,7 +147,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = service.Create(context.Background(), SignedInUser, dto)
|
_, err := service.Create(context.Background(), SignedInUser, dto)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pubdash, err := service.FindByDashboardUid(context.Background(), dashboard.OrgId, dashboard.Uid)
|
pubdash, err := service.FindByDashboardUid(context.Background(), dashboard.OrgId, dashboard.Uid)
|
||||||
@ -174,9 +171,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Validate pubdash has default time setting value", func(t *testing.T) {
|
t.Run("Validate pubdash has default time setting value", func(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
|
|
||||||
@ -196,7 +191,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = service.Create(context.Background(), SignedInUser, dto)
|
_, err := service.Create(context.Background(), SignedInUser, dto)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pubdash, err := service.FindByDashboardUid(context.Background(), dashboard.OrgId, dashboard.Uid)
|
pubdash, err := service.FindByDashboardUid(context.Background(), dashboard.OrgId, dashboard.Uid)
|
||||||
@ -206,9 +201,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Validate pubdash whose dashboard has template variables returns error", func(t *testing.T) {
|
t.Run("Validate pubdash whose dashboard has template variables returns error", func(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
templateVars := make([]map[string]interface{}, 1)
|
templateVars := make([]map[string]interface{}, 1)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars, nil)
|
||||||
@ -229,7 +222,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = service.Create(context.Background(), SignedInUser, dto)
|
_, err := service.Create(context.Background(), SignedInUser, dto)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -272,8 +265,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Returns error if public dashboard exists", func(t *testing.T) {
|
t.Run("Returns error if public dashboard exists", func(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotatest.New(false, nil))
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
|
|
||||||
@ -324,9 +316,7 @@ func TestCreatePublicDashboard(t *testing.T) {
|
|||||||
func TestUpdatePublicDashboard(t *testing.T) {
|
func TestUpdatePublicDashboard(t *testing.T) {
|
||||||
t.Run("Updating public dashboard", func(t *testing.T) {
|
t.Run("Updating public dashboard", func(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
|
|
||||||
@ -388,9 +378,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Updating set empty time settings", func(t *testing.T) {
|
t.Run("Updating set empty time settings", func(t *testing.T) {
|
||||||
sqlStore := db.InitTestDB(t)
|
sqlStore := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||||
dashboardStore, err := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
||||||
dsSvc "github.com/grafana/grafana/pkg/services/datasources/service"
|
dsSvc "github.com/grafana/grafana/pkg/services/datasources/service"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
@ -390,9 +389,7 @@ func setup(t *testing.T) *testContext {
|
|||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
ss := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
ss := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
ssvc := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
ssvc := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
quotaService := quotatest.New(false, nil)
|
ds := dsSvc.ProvideService(nil, ssvc, ss, nil, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
|
||||||
ds, err := dsSvc.ProvideService(nil, ssvc, ss, nil, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
fakeDatasourceService := &fakeDatasources.FakeDataSourceService{
|
fakeDatasourceService := &fakeDatasources.FakeDataSourceService{
|
||||||
DataSources: nil,
|
DataSources: nil,
|
||||||
SimulatePluginFailure: false,
|
SimulatePluginFailure: false,
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
package quota
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Context struct {
|
|
||||||
context.Context
|
|
||||||
TargetToSrv *TargetToSrv
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromContext(ctx context.Context, targetToSrv *TargetToSrv) Context {
|
|
||||||
if targetToSrv == nil {
|
|
||||||
targetToSrv = NewTargetToSrv()
|
|
||||||
}
|
|
||||||
return Context{Context: ctx, TargetToSrv: targetToSrv}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TargetToSrv struct {
|
|
||||||
mutex sync.RWMutex
|
|
||||||
m map[Target]TargetSrv
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTargetToSrv() *TargetToSrv {
|
|
||||||
return &TargetToSrv{m: make(map[Target]TargetSrv)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TargetToSrv) Get(target Target) (TargetSrv, bool) {
|
|
||||||
m.mutex.RLock()
|
|
||||||
defer m.mutex.RUnlock()
|
|
||||||
|
|
||||||
srv, ok := m.m[target]
|
|
||||||
return srv, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *TargetToSrv) Set(target Target, srv TargetSrv) {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
m.m[target] = srv
|
|
||||||
}
|
|
@ -1,216 +1,10 @@
|
|||||||
package quota
|
package quota
|
||||||
|
|
||||||
import (
|
import "errors"
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/util/errutil"
|
var ErrInvalidQuotaTarget = errors.New("invalid quota target")
|
||||||
)
|
|
||||||
|
|
||||||
var ErrBadRequest = errutil.NewBase(errutil.StatusBadRequest, "quota.bad-request")
|
|
||||||
var ErrInvalidTargetSrv = errutil.NewBase(errutil.StatusBadRequest, "quota.invalid-target")
|
|
||||||
var ErrInvalidScope = errutil.NewBase(errutil.StatusBadRequest, "quota.invalid-scope")
|
|
||||||
var ErrInvalidTarget = errutil.NewBase(errutil.StatusInternal, "quota.invalid-target-table")
|
|
||||||
var ErrTargetSrvConflict = errutil.NewBase(errutil.StatusBadRequest, "quota.target-srv-conflict")
|
|
||||||
var ErrDisabled = errutil.NewBase(errutil.StatusForbidden, "quota.disabled", errutil.WithPublicMessage("Quotas not enabled"))
|
|
||||||
var ErrInvalidTagFormat = errutil.NewBase(errutil.StatusInternal, "quota.invalid-invalid-tag-format")
|
|
||||||
|
|
||||||
type ScopeParameters struct {
|
type ScopeParameters struct {
|
||||||
OrgID int64
|
OrgID int64
|
||||||
UserID int64
|
UserID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Scope string
|
|
||||||
|
|
||||||
const (
|
|
||||||
GlobalScope Scope = "global"
|
|
||||||
OrgScope Scope = "org"
|
|
||||||
UserScope Scope = "user"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s Scope) Validate() error {
|
|
||||||
switch s {
|
|
||||||
case GlobalScope, OrgScope, UserScope:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return ErrInvalidScope.Errorf("bad scope: %s", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TargetSrv string
|
|
||||||
|
|
||||||
type Target string
|
|
||||||
|
|
||||||
const delimiter = ":"
|
|
||||||
|
|
||||||
// Tag is a string with the format <srv>:<target>:<scope>
|
|
||||||
type Tag string
|
|
||||||
|
|
||||||
func NewTag(srv TargetSrv, t Target, scope Scope) (Tag, error) {
|
|
||||||
if err := scope.Validate(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
tag := Tag(strings.Join([]string{string(srv), string(t), string(scope)}, delimiter))
|
|
||||||
return tag, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Tag) split() ([]string, error) {
|
|
||||||
parts := strings.SplitN(string(t), delimiter, -1)
|
|
||||||
if len(parts) != 3 {
|
|
||||||
return nil, ErrInvalidTagFormat.Errorf("tag format should be ^(?<srv>\\w):(?<target>\\w):(?<scope>\\w)$")
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Tag) GetSrv() (TargetSrv, error) {
|
|
||||||
parts, err := t.split()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return TargetSrv(parts[0]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Tag) GetTarget() (Target, error) {
|
|
||||||
parts, err := t.split()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return Target(parts[1]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Tag) GetScope() (Scope, error) {
|
|
||||||
parts, err := t.split()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return Scope(parts[2]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Item struct {
|
|
||||||
Tag Tag
|
|
||||||
Value int64
|
|
||||||
}
|
|
||||||
|
|
||||||
type Map struct {
|
|
||||||
mutex sync.RWMutex
|
|
||||||
m map[Tag]int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Set(tag Tag, limit int64) {
|
|
||||||
m.mutex.Lock()
|
|
||||||
defer m.mutex.Unlock()
|
|
||||||
|
|
||||||
if len(m.m) == 0 {
|
|
||||||
m.m = make(map[Tag]int64, 0)
|
|
||||||
}
|
|
||||||
m.m[tag] = limit
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Get(tag Tag) (int64, bool) {
|
|
||||||
m.mutex.RLock()
|
|
||||||
defer m.mutex.RUnlock()
|
|
||||||
|
|
||||||
limit, ok := m.m[tag]
|
|
||||||
return limit, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Merge(l2 *Map) {
|
|
||||||
l2.mutex.RLock()
|
|
||||||
defer l2.mutex.RUnlock()
|
|
||||||
|
|
||||||
for k, v := range l2.m {
|
|
||||||
// TODO check for conflicts?
|
|
||||||
m.Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Iter() <-chan Item {
|
|
||||||
m.mutex.RLock()
|
|
||||||
defer m.mutex.RUnlock()
|
|
||||||
|
|
||||||
ch := make(chan Item)
|
|
||||||
go func() {
|
|
||||||
defer close(ch)
|
|
||||||
for t, v := range m.m {
|
|
||||||
ch <- Item{Tag: t, Value: v}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Scopes() (map[Scope]struct{}, error) {
|
|
||||||
res := make(map[Scope]struct{})
|
|
||||||
for item := range m.Iter() {
|
|
||||||
scope, err := item.Tag.GetScope()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res[scope] = struct{}{}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Services() (map[TargetSrv]struct{}, error) {
|
|
||||||
res := make(map[TargetSrv]struct{})
|
|
||||||
for item := range m.Iter() {
|
|
||||||
srv, err := item.Tag.GetSrv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res[srv] = struct{}{}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Map) Targets() (map[Target]struct{}, error) {
|
|
||||||
res := make(map[Target]struct{})
|
|
||||||
for item := range m.Iter() {
|
|
||||||
target, err := item.Tag.GetTarget()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res[target] = struct{}{}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Quota struct {
|
|
||||||
Id int64
|
|
||||||
OrgId int64
|
|
||||||
UserId int64
|
|
||||||
Target string
|
|
||||||
Limit int64
|
|
||||||
Created time.Time
|
|
||||||
Updated time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type QuotaDTO struct {
|
|
||||||
OrgId int64 `json:"org_id,omitempty"`
|
|
||||||
UserId int64 `json:"user_id,omitempty"`
|
|
||||||
Target string `json:"target"`
|
|
||||||
Limit int64 `json:"limit"`
|
|
||||||
Used int64 `json:"used"`
|
|
||||||
Service string `json:"-"`
|
|
||||||
Scope string `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dto QuotaDTO) Tag() (Tag, error) {
|
|
||||||
return NewTag(TargetSrv(dto.Service), Target(dto.Target), Scope(dto.Scope))
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpdateQuotaCmd struct {
|
|
||||||
Target string `json:"target"`
|
|
||||||
Limit int64 `json:"limit"`
|
|
||||||
OrgID int64 `json:"-"`
|
|
||||||
UserID int64 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NewUsageReporter struct {
|
|
||||||
TargetSrv TargetSrv
|
|
||||||
DefaultLimits *Map
|
|
||||||
Reporter UsageReporterFunc
|
|
||||||
}
|
|
||||||
|
@ -7,24 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
// GetQuotasByScope returns the quota for the specific scope (global, organization, user)
|
QuotaReached(c *models.ReqContext, target string) (bool, error)
|
||||||
// If the scope is organization, the ID is expected to be the organisation ID.
|
CheckQuotaReached(ctx context.Context, target string, scopeParams *ScopeParameters) (bool, error)
|
||||||
// If the scope is user, the id is expected to be the user ID.
|
DeleteByUser(context.Context, int64) error
|
||||||
GetQuotasByScope(ctx context.Context, scope Scope, ID int64) ([]QuotaDTO, error)
|
|
||||||
// Update overrides the quota for a specific scope (global, organization, user).
|
|
||||||
// If the cmd.OrgID is set, then the organization quota are updated.
|
|
||||||
// If the cmd.UseID is set, then the user quota are updated.
|
|
||||||
Update(ctx context.Context, cmd *UpdateQuotaCmd) error
|
|
||||||
// QuotaReached is called by the quota middleware for applying quota enforcement to API handlers
|
|
||||||
QuotaReached(c *models.ReqContext, targetSrv TargetSrv) (bool, error)
|
|
||||||
// CheckQuotaReached checks if the quota limitations have been reached for a specific service
|
|
||||||
CheckQuotaReached(ctx context.Context, targetSrv TargetSrv, scopeParams *ScopeParameters) (bool, error)
|
|
||||||
// DeleteQuotaForUser deletes custom quota limitations for the user
|
|
||||||
DeleteQuotaForUser(ctx context.Context, userID int64) error
|
|
||||||
// DeleteByOrg(ctx context.Context, orgID int64) error
|
|
||||||
|
|
||||||
// RegisterQuotaReporter registers a service UsageReporterFunc, targets and their default limits
|
|
||||||
RegisterQuotaReporter(e *NewUsageReporter) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type UsageReporterFunc func(ctx context.Context, scopeParams *ScopeParameters) (*Map, error)
|
|
||||||
|
@ -2,81 +2,38 @@ package quotaimpl
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
"github.com/grafana/grafana/pkg/services/quota"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type serviceDisabled struct {
|
type Service struct {
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serviceDisabled) QuotaReached(c *models.ReqContext, targetSrv quota.TargetSrv) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serviceDisabled) GetQuotasByScope(ctx context.Context, scope quota.Scope, id int64) ([]quota.QuotaDTO, error) {
|
|
||||||
return nil, quota.ErrDisabled
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serviceDisabled) Update(ctx context.Context, cmd *quota.UpdateQuotaCmd) error {
|
|
||||||
return quota.ErrDisabled
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serviceDisabled) CheckQuotaReached(ctx context.Context, targetSrv quota.TargetSrv, scopeParams *quota.ScopeParameters) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serviceDisabled) DeleteQuotaForUser(ctx context.Context, userID int64) error {
|
|
||||||
return quota.ErrDisabled
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *serviceDisabled) RegisterQuotaReporter(e *quota.NewUsageReporter) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
store store
|
store store
|
||||||
|
authTokenService models.ActiveTokenService
|
||||||
Cfg *setting.Cfg
|
Cfg *setting.Cfg
|
||||||
|
SQLStore sqlstore.Store
|
||||||
Logger log.Logger
|
Logger log.Logger
|
||||||
|
|
||||||
mutex sync.RWMutex
|
|
||||||
reporters map[quota.TargetSrv]quota.UsageReporterFunc
|
|
||||||
|
|
||||||
defaultLimits *quota.Map
|
|
||||||
|
|
||||||
targetToSrv *quota.TargetToSrv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(db db.DB, cfg *setting.Cfg) quota.Service {
|
func ProvideService(db db.DB, cfg *setting.Cfg, tokenService models.ActiveTokenService, ss *sqlstore.SQLStore) quota.Service {
|
||||||
logger := log.New("quota_service")
|
return &Service{
|
||||||
s := service{
|
store: &sqlStore{db: db},
|
||||||
store: &sqlStore{db: db, logger: logger},
|
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Logger: logger,
|
authTokenService: tokenService,
|
||||||
reporters: make(map[quota.TargetSrv]quota.UsageReporterFunc),
|
SQLStore: ss,
|
||||||
defaultLimits: "a.Map{},
|
Logger: log.New("quota_service"),
|
||||||
targetToSrv: quota.NewTargetToSrv(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.IsDisabled() {
|
|
||||||
return &serviceDisabled{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) IsDisabled() bool {
|
|
||||||
return !s.Cfg.Quota.Enabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuotaReached checks that quota is reached for a target. Runs CheckQuotaReached and take context and scope parameters from the request context
|
// QuotaReached checks that quota is reached for a target. Runs CheckQuotaReached and take context and scope parameters from the request context
|
||||||
func (s *service) QuotaReached(c *models.ReqContext, targetSrv quota.TargetSrv) (bool, error) {
|
func (s *Service) QuotaReached(c *models.ReqContext, target string) (bool, error) {
|
||||||
|
if !s.Cfg.Quota.Enabled {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
// No request context means this is a background service, like LDAP Background Sync
|
// No request context means this is a background service, like LDAP Background Sync
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -89,129 +46,91 @@ func (s *service) QuotaReached(c *models.ReqContext, targetSrv quota.TargetSrv)
|
|||||||
UserID: c.UserID,
|
UserID: c.UserID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s.CheckQuotaReached(c.Req.Context(), targetSrv, params)
|
return s.CheckQuotaReached(c.Req.Context(), target, params)
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) GetQuotasByScope(ctx context.Context, scope quota.Scope, id int64) ([]quota.QuotaDTO, error) {
|
|
||||||
if err := scope.Validate(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
q := make([]quota.QuotaDTO, 0)
|
|
||||||
|
|
||||||
scopeParams := quota.ScopeParameters{}
|
|
||||||
if scope == quota.OrgScope {
|
|
||||||
scopeParams.OrgID = id
|
|
||||||
} else if scope == quota.UserScope {
|
|
||||||
scopeParams.UserID = id
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := s.getContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
customLimits, err := s.store.Get(c, &scopeParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := s.getUsage(ctx, &scopeParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for item := range s.defaultLimits.Iter() {
|
|
||||||
limit := item.Value
|
|
||||||
|
|
||||||
scp, err := item.Tag.GetScope()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if scp != scope {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if targetCustomLimit, ok := customLimits.Get(item.Tag); ok {
|
|
||||||
limit = targetCustomLimit
|
|
||||||
}
|
|
||||||
|
|
||||||
target, err := item.Tag.GetTarget()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
srv, err := item.Tag.GetSrv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
used, _ := u.Get(item.Tag)
|
|
||||||
q = append(q, quota.QuotaDTO{
|
|
||||||
Target: string(target),
|
|
||||||
Limit: limit,
|
|
||||||
OrgId: scopeParams.OrgID,
|
|
||||||
UserId: scopeParams.UserID,
|
|
||||||
Used: used,
|
|
||||||
Service: string(srv),
|
|
||||||
Scope: string(scope),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return q, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Update(ctx context.Context, cmd *quota.UpdateQuotaCmd) error {
|
|
||||||
targetFound := false
|
|
||||||
knownTargets, err := s.defaultLimits.Targets()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for t := range knownTargets {
|
|
||||||
if t == quota.Target(cmd.Target) {
|
|
||||||
targetFound = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !targetFound {
|
|
||||||
return quota.ErrInvalidTarget.Errorf("unknown quota target: %s", cmd.Target)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := s.getContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.store.Update(c, cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckQuotaReached check that quota is reached for a target. If ScopeParameters are not defined, only global scope is checked
|
// CheckQuotaReached check that quota is reached for a target. If ScopeParameters are not defined, only global scope is checked
|
||||||
func (s *service) CheckQuotaReached(ctx context.Context, targetSrv quota.TargetSrv, scopeParams *quota.ScopeParameters) (bool, error) {
|
func (s *Service) CheckQuotaReached(ctx context.Context, target string, scopeParams *quota.ScopeParameters) (bool, error) {
|
||||||
targetSrvLimits, err := s.getOverridenLimits(ctx, targetSrv, scopeParams)
|
if !s.Cfg.Quota.Enabled {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
// get the list of scopes that this target is valid for. Org, User, Global
|
||||||
|
scopes, err := s.getQuotaScopes(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
for _, scope := range scopes {
|
||||||
|
s.Logger.Debug("Checking quota", "target", target, "scope", scope)
|
||||||
|
|
||||||
usageReporterFunc, ok := s.getReporter(targetSrv)
|
switch scope.Name {
|
||||||
if !ok {
|
case "global":
|
||||||
return false, quota.ErrInvalidTargetSrv
|
if scope.DefaultLimit < 0 {
|
||||||
}
|
|
||||||
targetUsage, err := usageReporterFunc(ctx, scopeParams)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for t, limit := range targetSrvLimits {
|
|
||||||
switch {
|
|
||||||
case limit < 0:
|
|
||||||
continue
|
continue
|
||||||
case limit == 0:
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
u, ok := targetUsage.Get(t)
|
|
||||||
if !ok {
|
|
||||||
return false, fmt.Errorf("no usage for target:%s", t)
|
|
||||||
}
|
}
|
||||||
if u >= limit {
|
if scope.DefaultLimit == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if target == "session" {
|
||||||
|
usedSessions, err := s.authTokenService.ActiveTokenCount(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if usedSessions > scope.DefaultLimit {
|
||||||
|
s.Logger.Debug("Sessions limit reached", "active", usedSessions, "limit", scope.DefaultLimit)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
query := models.GetGlobalQuotaByTargetQuery{Target: scope.Target, UnifiedAlertingEnabled: s.Cfg.UnifiedAlerting.IsEnabled()}
|
||||||
|
// TODO : move GetGlobalQuotaByTarget to a global quota service
|
||||||
|
if err := s.SQLStore.GetGlobalQuotaByTarget(ctx, &query); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if query.Result.Used >= scope.DefaultLimit {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
case "org":
|
||||||
|
if scopeParams == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{
|
||||||
|
OrgId: scopeParams.OrgID,
|
||||||
|
Target: scope.Target,
|
||||||
|
Default: scope.DefaultLimit,
|
||||||
|
UnifiedAlertingEnabled: s.Cfg.UnifiedAlerting.IsEnabled(),
|
||||||
|
}
|
||||||
|
// TODO: move GetOrgQuotaByTarget from sqlstore to quota store
|
||||||
|
if err := s.SQLStore.GetOrgQuotaByTarget(ctx, &query); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if query.Result.Limit < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if query.Result.Limit == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Result.Used >= query.Result.Limit {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
case "user":
|
||||||
|
if scopeParams == nil || scopeParams.UserID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
query := models.GetUserQuotaByTargetQuery{UserId: scopeParams.UserID, Target: scope.Target, Default: scope.DefaultLimit, UnifiedAlertingEnabled: s.Cfg.UnifiedAlerting.IsEnabled()}
|
||||||
|
// TODO: move GetUserQuotaByTarget from sqlstore to quota store
|
||||||
|
if err := s.SQLStore.GetUserQuotaByTarget(ctx, &query); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if query.Result.Limit < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if query.Result.Limit == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if query.Result.Used >= query.Result.Limit {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,127 +138,68 @@ func (s *service) CheckQuotaReached(ctx context.Context, targetSrv quota.TargetS
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) DeleteQuotaForUser(ctx context.Context, userID int64) error {
|
func (s *Service) getQuotaScopes(target string) ([]models.QuotaScope, error) {
|
||||||
c, err := s.getContext(ctx)
|
scopes := make([]models.QuotaScope, 0)
|
||||||
if err != nil {
|
switch target {
|
||||||
return err
|
case "user":
|
||||||
}
|
scopes = append(scopes,
|
||||||
return s.store.DeleteByUser(c, userID)
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.User},
|
||||||
}
|
models.QuotaScope{Name: "org", Target: "org_user", DefaultLimit: s.Cfg.Quota.Org.User},
|
||||||
|
)
|
||||||
func (s *service) RegisterQuotaReporter(e *quota.NewUsageReporter) error {
|
return scopes, nil
|
||||||
s.mutex.Lock()
|
case "org":
|
||||||
defer s.mutex.Unlock()
|
scopes = append(scopes,
|
||||||
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.Org},
|
||||||
_, ok := s.reporters[e.TargetSrv]
|
models.QuotaScope{Name: "user", Target: "org_user", DefaultLimit: s.Cfg.Quota.User.Org},
|
||||||
if ok {
|
)
|
||||||
return quota.ErrTargetSrvConflict.Errorf("target service: %s already exists", e.TargetSrv)
|
return scopes, nil
|
||||||
}
|
case "dashboard":
|
||||||
|
scopes = append(scopes,
|
||||||
s.reporters[e.TargetSrv] = e.Reporter
|
models.QuotaScope{
|
||||||
|
Name: "global",
|
||||||
for item := range e.DefaultLimits.Iter() {
|
Target: target,
|
||||||
target, err := item.Tag.GetTarget()
|
DefaultLimit: s.Cfg.Quota.Global.Dashboard,
|
||||||
if err != nil {
|
},
|
||||||
return err
|
models.QuotaScope{
|
||||||
}
|
Name: "org",
|
||||||
srv, err := item.Tag.GetSrv()
|
Target: target,
|
||||||
if err != nil {
|
DefaultLimit: s.Cfg.Quota.Org.Dashboard,
|
||||||
return err
|
},
|
||||||
}
|
)
|
||||||
s.targetToSrv.Set(target, srv)
|
return scopes, nil
|
||||||
s.defaultLimits.Set(item.Tag, item.Value)
|
case "data_source":
|
||||||
}
|
scopes = append(scopes,
|
||||||
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.DataSource},
|
||||||
return nil
|
models.QuotaScope{Name: "org", Target: target, DefaultLimit: s.Cfg.Quota.Org.DataSource},
|
||||||
}
|
)
|
||||||
|
return scopes, nil
|
||||||
func (s *service) getReporter(target quota.TargetSrv) (quota.UsageReporterFunc, bool) {
|
case "api_key":
|
||||||
s.mutex.RLock()
|
scopes = append(scopes,
|
||||||
defer s.mutex.RUnlock()
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.ApiKey},
|
||||||
|
models.QuotaScope{Name: "org", Target: target, DefaultLimit: s.Cfg.Quota.Org.ApiKey},
|
||||||
r, ok := s.reporters[target]
|
)
|
||||||
return r, ok
|
return scopes, nil
|
||||||
}
|
case "session":
|
||||||
|
scopes = append(scopes,
|
||||||
type reporter struct {
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.Session},
|
||||||
target quota.TargetSrv
|
)
|
||||||
reporterFunc quota.UsageReporterFunc
|
return scopes, nil
|
||||||
}
|
case "alert_rule": // target need to match the respective database name
|
||||||
|
scopes = append(scopes,
|
||||||
func (s *service) getReporters() <-chan reporter {
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.AlertRule},
|
||||||
ch := make(chan reporter)
|
models.QuotaScope{Name: "org", Target: target, DefaultLimit: s.Cfg.Quota.Org.AlertRule},
|
||||||
go func() {
|
)
|
||||||
s.mutex.RLock()
|
return scopes, nil
|
||||||
defer func() {
|
case "file":
|
||||||
s.mutex.RUnlock()
|
scopes = append(scopes,
|
||||||
close(ch)
|
models.QuotaScope{Name: "global", Target: target, DefaultLimit: s.Cfg.Quota.Global.File},
|
||||||
}()
|
)
|
||||||
for t, r := range s.reporters {
|
return scopes, nil
|
||||||
ch <- reporter{target: t, reporterFunc: r}
|
default:
|
||||||
}
|
return scopes, quota.ErrInvalidQuotaTarget
|
||||||
}()
|
|
||||||
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) getOverridenLimits(ctx context.Context, targetSrv quota.TargetSrv, scopeParams *quota.ScopeParameters) (map[quota.Tag]int64, error) {
|
|
||||||
targetSrvLimits := make(map[quota.Tag]int64)
|
|
||||||
|
|
||||||
c, err := s.getContext(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
customLimits, err := s.store.Get(c, scopeParams)
|
|
||||||
if err != nil {
|
|
||||||
return targetSrvLimits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for item := range s.defaultLimits.Iter() {
|
|
||||||
srv, err := item.Tag.GetSrv()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if srv != targetSrv {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultLimit := item.Value
|
|
||||||
|
|
||||||
if customLimit, ok := customLimits.Get(item.Tag); ok {
|
|
||||||
targetSrvLimits[item.Tag] = customLimit
|
|
||||||
} else {
|
|
||||||
targetSrvLimits[item.Tag] = defaultLimit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return targetSrvLimits, nil
|
func (s *Service) DeleteByUser(ctx context.Context, userID int64) error {
|
||||||
}
|
return s.store.DeleteByUser(ctx, userID)
|
||||||
|
|
||||||
func (s *service) getUsage(ctx context.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
usage := "a.Map{}
|
|
||||||
g, ctx := errgroup.WithContext(ctx)
|
|
||||||
|
|
||||||
for r := range s.getReporters() {
|
|
||||||
r := r
|
|
||||||
g.Go(func() error {
|
|
||||||
u, err := r.reporterFunc(ctx, scopeParams)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
usage.Merge(u)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := g.Wait(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return usage, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) getContext(ctx context.Context) (quota.Context, error) {
|
|
||||||
return quota.FromContext(ctx, s.targetToSrv), nil
|
|
||||||
}
|
}
|
||||||
|
@ -3,481 +3,26 @@ package quotaimpl
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/routing"
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
|
||||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
|
||||||
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
|
||||||
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
|
||||||
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
||||||
dashboardStore "github.com/grafana/grafana/pkg/services/dashboards/database"
|
|
||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
|
||||||
dsservice "github.com/grafana/grafana/pkg/services/datasources/service"
|
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
||||||
"github.com/grafana/grafana/pkg/services/folder/foldertest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert"
|
|
||||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
|
||||||
ngalertmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
|
||||||
ngalerttests "github.com/grafana/grafana/pkg/services/ngalert/tests"
|
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
|
||||||
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
|
||||||
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
storesrv "github.com/grafana/grafana/pkg/services/store"
|
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/xorcare/pointer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQuotaService(t *testing.T) {
|
func TestQuotaService(t *testing.T) {
|
||||||
quotaStore := "atest.FakeQuotaStore{}
|
quotaStore := &FakeQuotaStore{}
|
||||||
quotaService := service{
|
quotaService := Service{
|
||||||
store: quotaStore,
|
store: quotaStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("delete quota", func(t *testing.T) {
|
t.Run("delete quota", func(t *testing.T) {
|
||||||
err := quotaService.DeleteQuotaForUser(context.Background(), 1)
|
err := quotaService.DeleteByUser(context.Background(), 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIntegrationQuotaCommandsAndQueries(t *testing.T) {
|
type FakeQuotaStore struct {
|
||||||
if testing.Short() {
|
ExpectedError error
|
||||||
t.Skip("skipping integration test")
|
|
||||||
}
|
|
||||||
sqlStore := sqlstore.InitTestDB(t)
|
|
||||||
sqlStore.Cfg.Quota = setting.QuotaSettings{
|
|
||||||
Enabled: true,
|
|
||||||
|
|
||||||
Org: setting.OrgQuota{
|
|
||||||
User: 2,
|
|
||||||
Dashboard: 3,
|
|
||||||
DataSource: 4,
|
|
||||||
ApiKey: 5,
|
|
||||||
AlertRule: 6,
|
|
||||||
},
|
|
||||||
User: setting.UserQuota{
|
|
||||||
Org: 7,
|
|
||||||
},
|
|
||||||
Global: setting.GlobalQuota{
|
|
||||||
Org: 8,
|
|
||||||
User: 9,
|
|
||||||
Dashboard: 10,
|
|
||||||
DataSource: 11,
|
|
||||||
ApiKey: 12,
|
|
||||||
Session: 13,
|
|
||||||
AlertRule: 14,
|
|
||||||
File: 15,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b := bus.ProvideBus(tracing.InitializeTracerForTest())
|
func (f *FakeQuotaStore) DeleteByUser(ctx context.Context, userID int64) error {
|
||||||
quotaService := ProvideService(sqlStore, sqlStore.Cfg)
|
return f.ExpectedError
|
||||||
orgService, err := orgimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
userService, err := userimpl.ProvideService(sqlStore, orgService, sqlStore.Cfg, nil, nil, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
setupEnv(t, sqlStore, b, quotaService)
|
|
||||||
|
|
||||||
u, err := userService.Create(context.Background(), &user.CreateUserCommand{
|
|
||||||
Name: "TestUser",
|
|
||||||
SkipOrgSetup: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
o, err := orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{
|
|
||||||
Name: "TestOrg",
|
|
||||||
UserID: u.ID,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// fetch global default limit/usage
|
|
||||||
defaultGlobalLimits := make(map[quota.Tag]int64)
|
|
||||||
existingGlobalUsage := make(map[quota.Tag]int64)
|
|
||||||
scope := quota.GlobalScope
|
|
||||||
result, err := quotaService.GetQuotasByScope(context.Background(), scope, 0)
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, r := range result {
|
|
||||||
tag, err := r.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
defaultGlobalLimits[tag] = r.Limit
|
|
||||||
existingGlobalUsage[tag] = r.Used
|
|
||||||
}
|
|
||||||
tag, err := quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgQuotaTarget), scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.Org, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.User, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.Dashboard, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(datasources.QuotaTargetSrv, datasources.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.DataSource, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.ApiKey, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(auth.QuotaTargetSrv, auth.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.Session, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(ngalertmodels.QuotaTargetSrv, ngalertmodels.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.AlertRule, defaultGlobalLimits[tag])
|
|
||||||
tag, err = quota.NewTag(storesrv.QuotaTargetSrv, storesrv.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Global.File, defaultGlobalLimits[tag])
|
|
||||||
|
|
||||||
// fetch default limit/usage for org
|
|
||||||
defaultOrgLimits := make(map[quota.Tag]int64)
|
|
||||||
existingOrgUsage := make(map[quota.Tag]int64)
|
|
||||||
scope = quota.OrgScope
|
|
||||||
result, err = quotaService.GetQuotasByScope(context.Background(), scope, o.ID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, r := range result {
|
|
||||||
tag, err := r.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
defaultOrgLimits[tag] = r.Limit
|
|
||||||
existingOrgUsage[tag] = r.Used
|
|
||||||
}
|
|
||||||
tag, err = quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Org.User, defaultOrgLimits[tag])
|
|
||||||
tag, err = quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Org.Dashboard, defaultOrgLimits[tag])
|
|
||||||
tag, err = quota.NewTag(datasources.QuotaTargetSrv, datasources.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Org.DataSource, defaultOrgLimits[tag])
|
|
||||||
tag, err = quota.NewTag(apikey.QuotaTargetSrv, apikey.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Org.ApiKey, defaultOrgLimits[tag])
|
|
||||||
tag, err = quota.NewTag(ngalertmodels.QuotaTargetSrv, ngalertmodels.QuotaTarget, scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.Org.AlertRule, defaultOrgLimits[tag])
|
|
||||||
|
|
||||||
// fetch default limit/usage for user
|
|
||||||
defaultUserLimits := make(map[quota.Tag]int64)
|
|
||||||
existingUserUsage := make(map[quota.Tag]int64)
|
|
||||||
scope = quota.UserScope
|
|
||||||
result, err = quotaService.GetQuotasByScope(context.Background(), scope, u.ID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, r := range result {
|
|
||||||
tag, err := r.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
defaultUserLimits[tag] = r.Limit
|
|
||||||
existingUserUsage[tag] = r.Used
|
|
||||||
}
|
|
||||||
tag, err = quota.NewTag(quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), scope)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, sqlStore.Cfg.Quota.User.Org, defaultUserLimits[tag])
|
|
||||||
|
|
||||||
t.Run("Given saved org quota for users", func(t *testing.T) {
|
|
||||||
// update quota for the created org and limit users to 1
|
|
||||||
var customOrgUserLimit int64 = 1
|
|
||||||
orgCmd := quota.UpdateQuotaCmd{
|
|
||||||
OrgID: o.ID,
|
|
||||||
Target: org.OrgUserQuotaTarget,
|
|
||||||
Limit: customOrgUserLimit,
|
|
||||||
}
|
|
||||||
err := quotaService.Update(context.Background(), &orgCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
t.Run("Should be able to get saved limit/usage for org users", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.OrgScope, "a.ScopeParameters{OrgID: o.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, customOrgUserLimit, q.Limit)
|
|
||||||
require.Equal(t, int64(1), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to get default org users limit/usage for unknown org", func(t *testing.T) {
|
|
||||||
unknownOrgID := -1
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.OrgScope, "a.ScopeParameters{OrgID: int64(unknownOrgID)})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, defaultOrgLimits[tag], q.Limit)
|
|
||||||
require.Equal(t, int64(0), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to get zero used org alert quota when table does not exist (ngalert is not enabled - default case)", func(t *testing.T) {
|
|
||||||
// disable Grafana Alerting
|
|
||||||
cfg := *sqlStore.Cfg
|
|
||||||
cfg.UnifiedAlerting = setting.UnifiedAlertingSettings{Enabled: pointer.Bool(false)}
|
|
||||||
|
|
||||||
quotaSrv := ProvideService(sqlStore, &cfg)
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaSrv, ngalertmodels.QuotaTargetSrv, ngalertmodels.QuotaTarget, quota.OrgScope, "a.ScopeParameters{OrgID: o.ID})
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, int64(0), q.Limit)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to quota list for org", func(t *testing.T) {
|
|
||||||
result, err := quotaService.GetQuotasByScope(context.Background(), quota.OrgScope, o.ID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, result, 5)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, res := range result {
|
|
||||||
tag, err := res.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
limit := defaultOrgLimits[tag]
|
|
||||||
used := existingOrgUsage[tag]
|
|
||||||
if res.Target == org.OrgUserQuotaTarget {
|
|
||||||
limit = customOrgUserLimit
|
|
||||||
used = 1 // one user in the created org
|
|
||||||
}
|
|
||||||
require.Equal(t, limit, res.Limit)
|
|
||||||
require.Equal(t, used, res.Used)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Given saved org quota for dashboards", func(t *testing.T) {
|
|
||||||
// update quota for the created org and limit dashboards to 1
|
|
||||||
var customOrgDashboardLimit int64 = 1
|
|
||||||
orgCmd := quota.UpdateQuotaCmd{
|
|
||||||
OrgID: o.ID,
|
|
||||||
Target: string(dashboards.QuotaTarget),
|
|
||||||
Limit: customOrgDashboardLimit,
|
|
||||||
}
|
|
||||||
err := quotaService.Update(context.Background(), &orgCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
t.Run("Should be able to get saved quota by org id and target", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.OrgScope, "a.ScopeParameters{OrgID: o.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, customOrgDashboardLimit, q.Limit)
|
|
||||||
require.Equal(t, existingOrgUsage[tag], q.Used)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Given saved user quota for org", func(t *testing.T) {
|
|
||||||
// update quota for the created user and limit orgs to 1
|
|
||||||
var customUserOrgsLimit int64 = 1
|
|
||||||
userQuotaCmd := quota.UpdateQuotaCmd{
|
|
||||||
UserID: u.ID,
|
|
||||||
Target: org.OrgUserQuotaTarget,
|
|
||||||
Limit: customUserOrgsLimit,
|
|
||||||
}
|
|
||||||
err := quotaService.Update(context.Background(), &userQuotaCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
t.Run("Should be able to get saved limit/usage for user orgs", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.UserScope, "a.ScopeParameters{UserID: u.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
require.Equal(t, customUserOrgsLimit, q.Limit)
|
|
||||||
require.Equal(t, int64(1), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to get default user orgs limit/usage for unknown user", func(t *testing.T) {
|
|
||||||
var unknownUserID int64 = -1
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.UserScope, "a.ScopeParameters{UserID: unknownUserID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, defaultUserLimits[tag], q.Limit)
|
|
||||||
require.Equal(t, int64(0), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to quota list for user", func(t *testing.T) {
|
|
||||||
result, err = quotaService.GetQuotasByScope(context.Background(), quota.UserScope, u.ID)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, result, 1)
|
|
||||||
for _, res := range result {
|
|
||||||
tag, err := res.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
limit := defaultUserLimits[tag]
|
|
||||||
used := existingUserUsage[tag]
|
|
||||||
if res.Target == org.OrgUserQuotaTarget {
|
|
||||||
limit = customUserOrgsLimit // customized quota limit.
|
|
||||||
used = 1 // one user in the created org
|
|
||||||
}
|
|
||||||
require.Equal(t, limit, res.Limit)
|
|
||||||
require.Equal(t, used, res.Used)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to global user quota", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope, "a.ScopeParameters{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, defaultGlobalLimits[tag], q.Limit)
|
|
||||||
require.Equal(t, int64(1), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to global org quota", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgQuotaTarget), quota.GlobalScope, "a.ScopeParameters{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, defaultGlobalLimits[tag], q.Limit)
|
|
||||||
require.Equal(t, int64(1), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to get zero used global alert quota when table does not exist (ngalert is not enabled - default case)", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, ngalertmodels.QuotaTargetSrv, ngalertmodels.QuotaTarget, quota.GlobalScope, "a.ScopeParameters{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, defaultGlobalLimits[tag], q.Limit)
|
|
||||||
require.Equal(t, int64(0), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Should be able to global dashboard quota", func(t *testing.T) {
|
|
||||||
q, err := getQuotaBySrvTargetScope(t, quotaService, dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.GlobalScope, "a.ScopeParameters{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
tag, err := q.Tag()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, defaultGlobalLimits[tag], q.Limit)
|
|
||||||
require.Equal(t, int64(0), q.Used)
|
|
||||||
})
|
|
||||||
|
|
||||||
// related: https://github.com/grafana/grafana/issues/14342
|
|
||||||
t.Run("Should org quota updating is successful even if it called multiple time", func(t *testing.T) {
|
|
||||||
// update quota for the created org and limit users to 1
|
|
||||||
var customOrgUserLimit int64 = 1
|
|
||||||
orgCmd := quota.UpdateQuotaCmd{
|
|
||||||
OrgID: o.ID,
|
|
||||||
Target: org.OrgUserQuotaTarget,
|
|
||||||
Limit: customOrgUserLimit,
|
|
||||||
}
|
|
||||||
err := quotaService.Update(context.Background(), &orgCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
query, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.OrgScope, "a.ScopeParameters{OrgID: o.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, customOrgUserLimit, query.Limit)
|
|
||||||
|
|
||||||
// XXX: resolution of `Updated` column is 1sec, so this makes delay
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
customOrgUserLimit = 2
|
|
||||||
orgCmd = quota.UpdateQuotaCmd{
|
|
||||||
OrgID: o.ID,
|
|
||||||
Target: org.OrgUserQuotaTarget,
|
|
||||||
Limit: customOrgUserLimit,
|
|
||||||
}
|
|
||||||
err = quotaService.Update(context.Background(), &orgCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
query, err = getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.OrgScope, "a.ScopeParameters{OrgID: o.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, customOrgUserLimit, query.Limit)
|
|
||||||
})
|
|
||||||
|
|
||||||
// related: https://github.com/grafana/grafana/issues/14342
|
|
||||||
t.Run("Should user quota updating is successful even if it called multiple time", func(t *testing.T) {
|
|
||||||
// update quota for the created org and limit users to 1
|
|
||||||
var customUserOrgLimit int64 = 1
|
|
||||||
userQuotaCmd := quota.UpdateQuotaCmd{
|
|
||||||
UserID: u.ID,
|
|
||||||
Target: org.OrgUserQuotaTarget,
|
|
||||||
Limit: customUserOrgLimit,
|
|
||||||
}
|
|
||||||
err := quotaService.Update(context.Background(), &userQuotaCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
query, err := getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.UserScope, "a.ScopeParameters{UserID: u.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, customUserOrgLimit, query.Limit)
|
|
||||||
|
|
||||||
// XXX: resolution of `Updated` column is 1sec, so this makes delay
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
customUserOrgLimit = 10
|
|
||||||
userQuotaCmd = quota.UpdateQuotaCmd{
|
|
||||||
UserID: u.ID,
|
|
||||||
Target: org.OrgUserQuotaTarget,
|
|
||||||
Limit: customUserOrgLimit,
|
|
||||||
}
|
|
||||||
err = quotaService.Update(context.Background(), &userQuotaCmd)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
query, err = getQuotaBySrvTargetScope(t, quotaService, quota.TargetSrv(org.QuotaTargetSrv), quota.Target(org.OrgUserQuotaTarget), quota.UserScope, "a.ScopeParameters{UserID: u.ID})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, customUserOrgLimit, query.Limit)
|
|
||||||
})
|
|
||||||
|
|
||||||
// TODO data_source, file
|
|
||||||
}
|
|
||||||
|
|
||||||
func getQuotaBySrvTargetScope(t *testing.T, quotaService quota.Service, srv quota.TargetSrv, target quota.Target, scope quota.Scope, scopeParams *quota.ScopeParameters) (quota.QuotaDTO, error) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
var id int64 = 0
|
|
||||||
switch {
|
|
||||||
case scope == quota.OrgScope:
|
|
||||||
id = scopeParams.OrgID
|
|
||||||
case scope == quota.UserScope:
|
|
||||||
id = scopeParams.UserID
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := quotaService.GetQuotasByScope(context.Background(), scope, id)
|
|
||||||
require.NoError(t, err)
|
|
||||||
for _, r := range result {
|
|
||||||
if r.Target != string(target) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Service != string(srv) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.Scope != string(scope) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, r.OrgId, scopeParams.OrgID)
|
|
||||||
require.Equal(t, r.UserId, scopeParams.UserID)
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
return quota.QuotaDTO{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupEnv(t *testing.T, sqlStore *sqlstore.SQLStore, b bus.Bus, quotaService quota.Service) {
|
|
||||||
_, err := apikeyimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
_, err = auth.ProvideActiveAuthTokenService(sqlStore.Cfg, sqlStore, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
_, err = dashboardStore.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
|
||||||
_, err = dsservice.ProvideService(sqlStore, secretsService, secretsStore, sqlStore.Cfg, featuremgmt.WithFeatures(), acmock.New().WithDisabled(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
m := metrics.NewNGAlert(prometheus.NewRegistry())
|
|
||||||
_, err = ngalert.ProvideService(
|
|
||||||
sqlStore.Cfg, &ngalerttests.FakeFeatures{}, nil, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, quotaService,
|
|
||||||
secretsService, nil, m, &foldertest.FakeService{}, &acmock.Mock{}, &dashboards.FakeDashboardService{}, nil, b, &acmock.Mock{}, annotationstest.NewFakeAnnotationsRepo(),
|
|
||||||
)
|
|
||||||
require.NoError(t, err)
|
|
||||||
_, err = storesrv.ProvideService(sqlStore, featuremgmt.WithFeatures(), sqlStore.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
@ -1,130 +1,23 @@
|
|||||||
package quotaimpl
|
package quotaimpl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"context"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
Get(ctx quota.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error)
|
DeleteByUser(context.Context, int64) error
|
||||||
Update(ctx quota.Context, cmd *quota.UpdateQuotaCmd) error
|
|
||||||
DeleteByUser(quota.Context, int64) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sqlStore struct {
|
type sqlStore struct {
|
||||||
db db.DB
|
db db.DB
|
||||||
logger log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) DeleteByUser(ctx quota.Context, userID int64) error {
|
func (ss *sqlStore) DeleteByUser(ctx context.Context, userID int64) error {
|
||||||
return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||||
var rawSQL = "DELETE FROM quota WHERE user_id = ?"
|
var rawSQL = "DELETE FROM quota WHERE user_id = ?"
|
||||||
_, err := sess.Exec(rawSQL, userID)
|
_, err := sess.Exec(rawSQL, userID)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) Get(ctx quota.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
limits := quota.Map{}
|
|
||||||
if scopeParams.OrgID != 0 {
|
|
||||||
orgLimits, err := ss.getOrgScopeQuota(ctx, scopeParams.OrgID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
limits.Merge(orgLimits)
|
|
||||||
}
|
|
||||||
|
|
||||||
if scopeParams.UserID != 0 {
|
|
||||||
userLimits, err := ss.getUserScopeQuota(ctx, scopeParams.UserID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
limits.Merge(userLimits)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *sqlStore) Update(ctx quota.Context, cmd *quota.UpdateQuotaCmd) error {
|
|
||||||
return ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
// Check if quota is already defined in the DB
|
|
||||||
quota := quota.Quota{
|
|
||||||
Target: cmd.Target,
|
|
||||||
UserId: cmd.UserID,
|
|
||||||
OrgId: cmd.OrgID,
|
|
||||||
}
|
|
||||||
has, err := sess.Get("a)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
quota.Updated = time.Now()
|
|
||||||
quota.Limit = cmd.Limit
|
|
||||||
if !has {
|
|
||||||
quota.Created = time.Now()
|
|
||||||
// No quota in the DB for this target, so create a new one.
|
|
||||||
if _, err := sess.Insert("a); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// update existing quota entry in the DB.
|
|
||||||
_, err := sess.ID(quota.Id).Update("a)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *sqlStore) getUserScopeQuota(ctx quota.Context, userID int64) (*quota.Map, error) {
|
|
||||||
r := quota.Map{}
|
|
||||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
quotas := make([]*quota.Quota, 0)
|
|
||||||
if err := sess.Table("quota").Where("user_id=? AND org_id=0", userID).Find("as); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, q := range quotas {
|
|
||||||
srv, ok := ctx.TargetToSrv.Get(quota.Target(q.Target))
|
|
||||||
if !ok {
|
|
||||||
ss.logger.Info("failed to get service for target", "target", q.Target)
|
|
||||||
}
|
|
||||||
tag, err := quota.NewTag(srv, quota.Target(q.Target), quota.UserScope)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Set(tag, q.Limit)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return &r, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *sqlStore) getOrgScopeQuota(ctx quota.Context, OrgID int64) (*quota.Map, error) {
|
|
||||||
r := quota.Map{}
|
|
||||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
quotas := make([]*quota.Quota, 0)
|
|
||||||
if err := sess.Table("quota").Where("user_id=0 AND org_id=?", OrgID).Find("as); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, q := range quotas {
|
|
||||||
srv, ok := ctx.TargetToSrv.Get(quota.Target(q.Target))
|
|
||||||
if !ok {
|
|
||||||
ss.logger.Info("failed to get service for target", "target", q.Target)
|
|
||||||
}
|
|
||||||
tag, err := quota.NewTag(srv, quota.Target(q.Target), quota.OrgScope)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
r.Set(tag, q.Limit)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return &r, err
|
|
||||||
}
|
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIntegrationQuotaDataAccess(t *testing.T) {
|
func TestIntegrationQuotaDataAccess(t *testing.T) {
|
||||||
@ -21,8 +20,7 @@ func TestIntegrationQuotaDataAccess(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run("quota deleted", func(t *testing.T) {
|
t.Run("quota deleted", func(t *testing.T) {
|
||||||
ctx := quota.FromContext(context.Background(), "a.TargetToSrv{})
|
err := quotaStore.DeleteByUser(context.Background(), 1)
|
||||||
err := quotaStore.DeleteByUser(ctx, 1)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -12,46 +12,18 @@ type FakeQuotaService struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(reached bool, err error) *FakeQuotaService {
|
func NewQuotaServiceFake() *FakeQuotaService {
|
||||||
return &FakeQuotaService{reached, err}
|
return &FakeQuotaService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeQuotaService) GetQuotasByScope(ctx context.Context, scope quota.Scope, id int64) ([]quota.QuotaDTO, error) {
|
func (f *FakeQuotaService) QuotaReached(c *models.ReqContext, target string) (bool, error) {
|
||||||
return []quota.QuotaDTO{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeQuotaService) Update(ctx context.Context, cmd *quota.UpdateQuotaCmd) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeQuotaService) QuotaReached(c *models.ReqContext, target quota.TargetSrv) (bool, error) {
|
|
||||||
return f.reached, f.err
|
return f.reached, f.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeQuotaService) CheckQuotaReached(c context.Context, target quota.TargetSrv, params *quota.ScopeParameters) (bool, error) {
|
func (f *FakeQuotaService) CheckQuotaReached(c context.Context, target string, params *quota.ScopeParameters) (bool, error) {
|
||||||
return f.reached, f.err
|
return f.reached, f.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeQuotaService) DeleteQuotaForUser(c context.Context, userID int64) error {
|
func (f *FakeQuotaService) DeleteByUser(c context.Context, userID int64) error {
|
||||||
return f.err
|
return f.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeQuotaService) RegisterQuotaReporter(e *quota.NewUsageReporter) error {
|
|
||||||
return f.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type FakeQuotaStore struct {
|
|
||||||
ExpectedError error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeQuotaStore) DeleteByUser(ctx quota.Context, userID int64) error {
|
|
||||||
return f.ExpectedError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeQuotaStore) Get(ctx quota.Context, scopeParams *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
return nil, f.ExpectedError
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FakeQuotaStore) Update(ctx quota.Context, cmd *quota.UpdateQuotaCmd) error {
|
|
||||||
return f.ExpectedError
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/kvstore"
|
"github.com/grafana/grafana/pkg/infra/kvstore"
|
||||||
@ -14,7 +13,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/datasources"
|
"github.com/grafana/grafana/pkg/services/datasources"
|
||||||
dsservice "github.com/grafana/grafana/pkg/services/datasources/service"
|
dsservice "github.com/grafana/grafana/pkg/services/datasources/service"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
@ -29,9 +27,7 @@ func SetupTestDataSourceSecretMigrationService(t *testing.T, sqlStore db.DB, kvS
|
|||||||
features = featuremgmt.WithFeatures(featuremgmt.FlagDisableSecretsCompatibility, true)
|
features = featuremgmt.WithFeatures(featuremgmt.FlagDisableSecretsCompatibility, true)
|
||||||
}
|
}
|
||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := dsservice.ProvideService(sqlStore, secretsService, secretsStore, cfg, features, acmock.New().WithDisabled(), acmock.NewMockedPermissionsService())
|
||||||
dsService, err := dsservice.ProvideService(sqlStore, secretsService, secretsStore, cfg, features, acmock.New().WithDisabled(), acmock.NewMockedPermissionsService(), quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
migService := ProvideDataSourceMigrationService(dsService, kvStore, features)
|
migService := ProvideDataSourceMigrationService(dsService, kvStore, features)
|
||||||
return migService
|
return migService
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/licensing"
|
"github.com/grafana/grafana/pkg/services/licensing"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||||
@ -45,12 +44,9 @@ var (
|
|||||||
|
|
||||||
func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
||||||
store := db.InitTestDB(t)
|
store := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(store, store.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
kvStore := kvstore.ProvideService(store)
|
kvStore := kvstore.ProvideService(store)
|
||||||
orgService, err := orgimpl.ProvideService(store, setting.NewCfg(), quotaService)
|
orgService := orgimpl.ProvideService(store, setting.NewCfg())
|
||||||
require.NoError(t, err)
|
|
||||||
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, orgService)
|
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, orgService)
|
||||||
svcmock := tests.ServiceAccountMock{}
|
svcmock := tests.ServiceAccountMock{}
|
||||||
|
|
||||||
@ -61,7 +57,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
orgCmd := &models.CreateOrgCommand{Name: "Some Test Org"}
|
orgCmd := &models.CreateOrgCommand{Name: "Some Test Org"}
|
||||||
err = store.CreateOrg(context.Background(), orgCmd)
|
err := store.CreateOrg(context.Background(), orgCmd)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
type testCreateSATestCase struct {
|
type testCreateSATestCase struct {
|
||||||
@ -216,9 +212,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
|||||||
func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) {
|
func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) {
|
||||||
store := db.InitTestDB(t)
|
store := db.InitTestDB(t)
|
||||||
kvStore := kvstore.ProvideService(store)
|
kvStore := kvstore.ProvideService(store)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(store, store.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
||||||
svcmock := tests.ServiceAccountMock{}
|
svcmock := tests.ServiceAccountMock{}
|
||||||
|
|
||||||
@ -290,9 +284,7 @@ func setupTestServer(t *testing.T, svc *tests.ServiceAccountMock,
|
|||||||
sqlStore db.DB, saStore serviceaccounts.Store) (*web.Mux, *ServiceAccountsAPI) {
|
sqlStore db.DB, saStore serviceaccounts.Store) (*web.Mux, *ServiceAccountsAPI) {
|
||||||
cfg := setting.NewCfg()
|
cfg := setting.NewCfg()
|
||||||
teamSvc := teamimpl.ProvideService(sqlStore, cfg)
|
teamSvc := teamimpl.ProvideService(sqlStore, cfg)
|
||||||
|
userSvc := userimpl.ProvideService(sqlStore, nil, cfg, teamimpl.ProvideService(sqlStore, cfg), nil)
|
||||||
userSvc, err := userimpl.ProvideService(sqlStore, nil, cfg, teamimpl.ProvideService(sqlStore, cfg), nil, quotatest.New(false, nil))
|
|
||||||
require.NoError(t, err)
|
|
||||||
saPermissionService, err := ossaccesscontrol.ProvideServiceAccountPermissions(
|
saPermissionService, err := ossaccesscontrol.ProvideServiceAccountPermissions(
|
||||||
cfg, routing.NewRouteRegister(), sqlStore, acmock, &licensing.OSSLicensingService{}, saStore, acmock, teamSvc, userSvc)
|
cfg, routing.NewRouteRegister(), sqlStore, acmock, &licensing.OSSLicensingService{}, saStore, acmock, teamSvc, userSvc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -324,9 +316,7 @@ func setupTestServer(t *testing.T, svc *tests.ServiceAccountMock,
|
|||||||
|
|
||||||
func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
||||||
store := db.InitTestDB(t)
|
store := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(store, store.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
kvStore := kvstore.ProvideService(store)
|
kvStore := kvstore.ProvideService(store)
|
||||||
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
||||||
svcmock := tests.ServiceAccountMock{}
|
svcmock := tests.ServiceAccountMock{}
|
||||||
@ -418,9 +408,7 @@ func newString(s string) *string {
|
|||||||
|
|
||||||
func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
||||||
store := db.InitTestDB(t)
|
store := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(store, store.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
kvStore := kvstore.ProvideService(store)
|
kvStore := kvstore.ProvideService(store)
|
||||||
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
||||||
svcmock := tests.ServiceAccountMock{}
|
svcmock := tests.ServiceAccountMock{}
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||||
@ -55,9 +54,7 @@ func createTokenforSA(t *testing.T, store serviceaccounts.Store, keyName string,
|
|||||||
|
|
||||||
func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
||||||
store := db.InitTestDB(t)
|
store := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(store, store.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
kvStore := kvstore.ProvideService(store)
|
kvStore := kvstore.ProvideService(store)
|
||||||
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
||||||
svcmock := tests.ServiceAccountMock{}
|
svcmock := tests.ServiceAccountMock{}
|
||||||
@ -174,9 +171,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
|||||||
|
|
||||||
func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
||||||
store := db.InitTestDB(t)
|
store := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(store, store.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(store, store.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
kvStore := kvstore.ProvideService(store)
|
kvStore := kvstore.ProvideService(store)
|
||||||
svcMock := &tests.ServiceAccountMock{}
|
svcMock := &tests.ServiceAccountMock{}
|
||||||
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
saStore := database.ProvideServiceAccountsStore(store, apiKeyService, kvStore, nil)
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
@ -113,12 +112,9 @@ func TestStore_DeleteServiceAccount(t *testing.T) {
|
|||||||
func setupTestDatabase(t *testing.T) (*sqlstore.SQLStore, *ServiceAccountsStoreImpl) {
|
func setupTestDatabase(t *testing.T) (*sqlstore.SQLStore, *ServiceAccountsStoreImpl) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
db := db.InitTestDB(t)
|
db := db.InitTestDB(t)
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(db, db.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(db, db.Cfg, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
kvStore := kvstore.ProvideService(db)
|
kvStore := kvstore.ProvideService(db)
|
||||||
orgService, err := orgimpl.ProvideService(db, setting.NewCfg(), quotaService)
|
orgService := orgimpl.ProvideService(db, setting.NewCfg())
|
||||||
require.NoError(t, err)
|
|
||||||
return db, ProvideServiceAccountsStore(db, apiKeyService, kvStore, orgService)
|
return db, ProvideServiceAccountsStore(db, apiKeyService, kvStore, orgService)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
"github.com/grafana/grafana/pkg/services/apikey/apikeyimpl"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@ -71,10 +70,8 @@ func SetupApiKey(t *testing.T, sqlStore *sqlstore.SQLStore, testKey TestApiKey)
|
|||||||
addKeyCmd.Key = "secret"
|
addKeyCmd.Key = "secret"
|
||||||
}
|
}
|
||||||
|
|
||||||
quotaService := quotatest.New(false, nil)
|
apiKeyService := apikeyimpl.ProvideService(sqlStore, sqlStore.Cfg)
|
||||||
apiKeyService, err := apikeyimpl.ProvideService(sqlStore, sqlStore.Cfg, quotaService)
|
err := apiKeyService.AddAPIKey(context.Background(), addKeyCmd)
|
||||||
require.NoError(t, err)
|
|
||||||
err = apiKeyService.AddAPIKey(context.Background(), addKeyCmd)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if testKey.IsExpired {
|
if testKey.IsExpired {
|
||||||
|
@ -98,6 +98,34 @@ func (m *SQLStoreMock) WithNewDbSession(ctx context.Context, callback sqlstore.D
|
|||||||
return m.ExpectedError
|
return m.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) GetOrgQuotas(ctx context.Context, query *models.GetOrgQuotasQuery) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) UpdateOrgQuota(ctx context.Context, cmd *models.UpdateOrgQuotaCmd) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) GetUserQuotaByTarget(ctx context.Context, query *models.GetUserQuotaByTargetQuery) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) GetUserQuotas(ctx context.Context, query *models.GetUserQuotasQuery) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) UpdateUserQuota(ctx context.Context, cmd *models.UpdateUserQuotaCmd) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SQLStoreMock) GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error {
|
||||||
|
return m.ExpectedError
|
||||||
|
}
|
||||||
|
|
||||||
func (m *SQLStoreMock) WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
|
func (m *SQLStoreMock) WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
|
||||||
return m.ExpectedError
|
return m.ExpectedError
|
||||||
}
|
}
|
||||||
|
315
pkg/services/sqlstore/quota.go
Normal file
315
pkg/services/sqlstore/quota.go
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
package sqlstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
alertRuleTarget = "alert_rule"
|
||||||
|
dashboardTarget = "dashboard"
|
||||||
|
filesTarget = "file"
|
||||||
|
)
|
||||||
|
|
||||||
|
type targetCount struct {
|
||||||
|
Count int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error {
|
||||||
|
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
quota := models.Quota{
|
||||||
|
Target: query.Target,
|
||||||
|
OrgId: query.OrgId,
|
||||||
|
}
|
||||||
|
has, err := sess.Get("a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
|
quota.Limit = query.Default
|
||||||
|
}
|
||||||
|
|
||||||
|
var used int64
|
||||||
|
if query.Target != alertRuleTarget || query.UnifiedAlertingEnabled {
|
||||||
|
// get quota used.
|
||||||
|
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM %s WHERE org_id=?",
|
||||||
|
dialect.Quote(query.Target))
|
||||||
|
|
||||||
|
if query.Target == dashboardTarget {
|
||||||
|
rawSQL += fmt.Sprintf(" AND is_folder=%s", dialect.BooleanStr(false))
|
||||||
|
}
|
||||||
|
// need to account for removing service accounts from the user table
|
||||||
|
if query.Target == "org_user" {
|
||||||
|
rawSQL = fmt.Sprintf("SELECT COUNT(*) as count from (select user_id from %s where org_id=? AND user_id IN (SELECT id as user_id FROM %s WHERE is_service_account=%s)) as subq",
|
||||||
|
dialect.Quote(query.Target),
|
||||||
|
dialect.Quote("user"),
|
||||||
|
dialect.BooleanStr(false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
resp := make([]*targetCount, 0)
|
||||||
|
if err := sess.SQL(rawSQL, query.OrgId).Find(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
used = resp[0].Count
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Result = &models.OrgQuotaDTO{
|
||||||
|
Target: query.Target,
|
||||||
|
Limit: quota.Limit,
|
||||||
|
OrgId: query.OrgId,
|
||||||
|
Used: used,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) GetOrgQuotas(ctx context.Context, query *models.GetOrgQuotasQuery) error {
|
||||||
|
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
quotas := make([]*models.Quota, 0)
|
||||||
|
if err := sess.Table("quota").Where("org_id=? AND user_id=0", query.OrgId).Find("as); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultQuotas := setting.Quota.Org.ToMap()
|
||||||
|
|
||||||
|
seenTargets := make(map[string]bool)
|
||||||
|
for _, q := range quotas {
|
||||||
|
seenTargets[q.Target] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for t, v := range defaultQuotas {
|
||||||
|
if _, ok := seenTargets[t]; !ok {
|
||||||
|
quotas = append(quotas, &models.Quota{
|
||||||
|
OrgId: query.OrgId,
|
||||||
|
Target: t,
|
||||||
|
Limit: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]*models.OrgQuotaDTO, len(quotas))
|
||||||
|
for i, q := range quotas {
|
||||||
|
var used int64
|
||||||
|
var rawSQL string
|
||||||
|
if q.Target != alertRuleTarget || query.UnifiedAlertingEnabled {
|
||||||
|
// get quota used.
|
||||||
|
rawSQL = fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", dialect.Quote(q.Target))
|
||||||
|
|
||||||
|
// need to account for removing service accounts from the user table
|
||||||
|
if q.Target == "org_user" {
|
||||||
|
rawSQL = fmt.Sprintf("SELECT COUNT(*) as count from (select user_id from %s where org_id=? AND user_id IN (SELECT id as user_id FROM %s WHERE is_service_account=%s)) as subq",
|
||||||
|
dialect.Quote(q.Target),
|
||||||
|
dialect.Quote("user"),
|
||||||
|
dialect.BooleanStr(false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
resp := make([]*targetCount, 0)
|
||||||
|
if err := sess.SQL(rawSQL, q.OrgId).Find(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
used = resp[0].Count
|
||||||
|
}
|
||||||
|
result[i] = &models.OrgQuotaDTO{
|
||||||
|
Target: q.Target,
|
||||||
|
Limit: q.Limit,
|
||||||
|
OrgId: q.OrgId,
|
||||||
|
Used: used,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query.Result = result
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) UpdateOrgQuota(ctx context.Context, cmd *models.UpdateOrgQuotaCmd) error {
|
||||||
|
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
// Check if quota is already defined in the DB
|
||||||
|
quota := models.Quota{
|
||||||
|
Target: cmd.Target,
|
||||||
|
OrgId: cmd.OrgId,
|
||||||
|
}
|
||||||
|
has, err := sess.Get("a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
quota.Updated = time.Now()
|
||||||
|
quota.Limit = cmd.Limit
|
||||||
|
if !has {
|
||||||
|
quota.Created = time.Now()
|
||||||
|
// No quota in the DB for this target, so create a new one.
|
||||||
|
if _, err := sess.Insert("a); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// update existing quota entry in the DB.
|
||||||
|
_, err := sess.ID(quota.Id).Update("a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) GetUserQuotaByTarget(ctx context.Context, query *models.GetUserQuotaByTargetQuery) error {
|
||||||
|
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
quota := models.Quota{
|
||||||
|
Target: query.Target,
|
||||||
|
UserId: query.UserId,
|
||||||
|
}
|
||||||
|
has, err := sess.Get("a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if !has {
|
||||||
|
quota.Limit = query.Default
|
||||||
|
}
|
||||||
|
|
||||||
|
var used int64
|
||||||
|
if query.Target != alertRuleTarget || query.UnifiedAlertingEnabled {
|
||||||
|
// get quota used.
|
||||||
|
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where user_id=?", dialect.Quote(query.Target))
|
||||||
|
resp := make([]*targetCount, 0)
|
||||||
|
if err := sess.SQL(rawSQL, query.UserId).Find(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
used = resp[0].Count
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Result = &models.UserQuotaDTO{
|
||||||
|
Target: query.Target,
|
||||||
|
Limit: quota.Limit,
|
||||||
|
UserId: query.UserId,
|
||||||
|
Used: used,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) GetUserQuotas(ctx context.Context, query *models.GetUserQuotasQuery) error {
|
||||||
|
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
quotas := make([]*models.Quota, 0)
|
||||||
|
if err := sess.Table("quota").Where("user_id=? AND org_id=0", query.UserId).Find("as); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultQuotas := setting.Quota.User.ToMap()
|
||||||
|
|
||||||
|
seenTargets := make(map[string]bool)
|
||||||
|
for _, q := range quotas {
|
||||||
|
seenTargets[q.Target] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for t, v := range defaultQuotas {
|
||||||
|
if _, ok := seenTargets[t]; !ok {
|
||||||
|
quotas = append(quotas, &models.Quota{
|
||||||
|
UserId: query.UserId,
|
||||||
|
Target: t,
|
||||||
|
Limit: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]*models.UserQuotaDTO, len(quotas))
|
||||||
|
for i, q := range quotas {
|
||||||
|
var used int64
|
||||||
|
if q.Target != alertRuleTarget || query.UnifiedAlertingEnabled {
|
||||||
|
// get quota used.
|
||||||
|
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where user_id=?", dialect.Quote(q.Target))
|
||||||
|
resp := make([]*targetCount, 0)
|
||||||
|
if err := sess.SQL(rawSQL, q.UserId).Find(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
used = resp[0].Count
|
||||||
|
}
|
||||||
|
result[i] = &models.UserQuotaDTO{
|
||||||
|
Target: q.Target,
|
||||||
|
Limit: q.Limit,
|
||||||
|
UserId: q.UserId,
|
||||||
|
Used: used,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query.Result = result
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) UpdateUserQuota(ctx context.Context, cmd *models.UpdateUserQuotaCmd) error {
|
||||||
|
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
// Check if quota is already defined in the DB
|
||||||
|
quota := models.Quota{
|
||||||
|
Target: cmd.Target,
|
||||||
|
UserId: cmd.UserId,
|
||||||
|
}
|
||||||
|
has, err := sess.Get("a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
quota.Updated = time.Now()
|
||||||
|
quota.Limit = cmd.Limit
|
||||||
|
if !has {
|
||||||
|
quota.Created = time.Now()
|
||||||
|
// No quota in the DB for this target, so create a new one.
|
||||||
|
if _, err := sess.Insert("a); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// update existing quota entry in the DB.
|
||||||
|
_, err := sess.ID(quota.Id).Update("a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SQLStore) GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error {
|
||||||
|
return ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||||
|
var used int64
|
||||||
|
|
||||||
|
if query.Target == filesTarget {
|
||||||
|
// get quota used.
|
||||||
|
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM %s",
|
||||||
|
dialect.Quote("file"))
|
||||||
|
|
||||||
|
notFolderCondition := fmt.Sprintf(" WHERE path NOT LIKE '%s'", "%/")
|
||||||
|
resp := make([]*targetCount, 0)
|
||||||
|
if err := sess.SQL(rawSQL + notFolderCondition).Find(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
used = resp[0].Count
|
||||||
|
} else if query.Target != alertRuleTarget || query.UnifiedAlertingEnabled {
|
||||||
|
// get quota used.
|
||||||
|
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM %s",
|
||||||
|
dialect.Quote(query.Target))
|
||||||
|
|
||||||
|
if query.Target == dashboardTarget {
|
||||||
|
rawSQL += fmt.Sprintf(" WHERE is_folder=%s", dialect.BooleanStr(false))
|
||||||
|
}
|
||||||
|
// removing service accounts from count
|
||||||
|
if query.Target == dialect.Quote("user") {
|
||||||
|
rawSQL += fmt.Sprintf(" WHERE is_service_account=%s", dialect.BooleanStr(false))
|
||||||
|
}
|
||||||
|
resp := make([]*targetCount, 0)
|
||||||
|
if err := sess.SQL(rawSQL).Find(&resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
used = resp[0].Count
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Result = &models.GlobalQuotaDTO{
|
||||||
|
Target: query.Target,
|
||||||
|
Limit: query.Default,
|
||||||
|
Used: used,
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
301
pkg/services/sqlstore/quota_test.go
Normal file
301
pkg/services/sqlstore/quota_test.go
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
package sqlstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIntegrationQuotaCommandsAndQueries(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test")
|
||||||
|
}
|
||||||
|
sqlStore := InitTestDB(t)
|
||||||
|
userId := int64(1)
|
||||||
|
orgId := int64(0)
|
||||||
|
|
||||||
|
setting.Quota = setting.QuotaSettings{
|
||||||
|
Enabled: true,
|
||||||
|
Org: &setting.OrgQuota{
|
||||||
|
User: 5,
|
||||||
|
Dashboard: 5,
|
||||||
|
DataSource: 5,
|
||||||
|
ApiKey: 5,
|
||||||
|
AlertRule: 5,
|
||||||
|
},
|
||||||
|
User: &setting.UserQuota{
|
||||||
|
Org: 5,
|
||||||
|
},
|
||||||
|
Global: &setting.GlobalQuota{
|
||||||
|
Org: 5,
|
||||||
|
User: 5,
|
||||||
|
Dashboard: 5,
|
||||||
|
DataSource: 5,
|
||||||
|
ApiKey: 5,
|
||||||
|
Session: 5,
|
||||||
|
AlertRule: 5,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
createUserCmd := user.CreateUserCommand{
|
||||||
|
Name: "TestUser",
|
||||||
|
OrgID: orgId,
|
||||||
|
SkipOrgSetup: true,
|
||||||
|
}
|
||||||
|
user, err := sqlStore.CreateUser(context.Background(), createUserCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// create a new org and add user_id 1 as admin.
|
||||||
|
// we will then have an org with 1 user. and a user
|
||||||
|
// with 1 org.
|
||||||
|
userCmd := models.CreateOrgCommand{
|
||||||
|
Name: "TestOrg",
|
||||||
|
UserId: user.ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sqlStore.CreateOrg(context.Background(), &userCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
orgId = userCmd.Result.Id
|
||||||
|
|
||||||
|
t.Run("Given saved org quota for users", func(t *testing.T) {
|
||||||
|
orgCmd := models.UpdateOrgQuotaCmd{
|
||||||
|
OrgId: orgId,
|
||||||
|
Target: "org_user",
|
||||||
|
Limit: 10,
|
||||||
|
}
|
||||||
|
err := sqlStore.UpdateOrgQuota(context.Background(), &orgCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("Should be able to get saved quota by org id and target", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(10), query.Result.Limit)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get default quota by org id and target", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: 123, Target: "org_user", Default: 11}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(11), query.Result.Limit)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get used org quota when rows exist", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 11}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(1), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get used org quota when no rows exist", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: 2, Target: "org_user", Default: 11}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(0), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get zero used org alert quota when table does not exist (ngalert is not enabled - default case)", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: 2, Target: "alert", Default: 11}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(0), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to quota list for org", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotasQuery{OrgId: orgId}
|
||||||
|
err = sqlStore.GetOrgQuotas(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, query.Result, 5)
|
||||||
|
for _, res := range query.Result {
|
||||||
|
limit := int64(5) // default quota limit
|
||||||
|
used := int64(0)
|
||||||
|
if res.Target == "org_user" {
|
||||||
|
limit = 10 // customized quota limit.
|
||||||
|
used = 1
|
||||||
|
}
|
||||||
|
require.Equal(t, limit, res.Limit)
|
||||||
|
require.Equal(t, used, res.Used)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Given saved org quota for dashboards", func(t *testing.T) {
|
||||||
|
orgCmd := models.UpdateOrgQuotaCmd{
|
||||||
|
OrgId: orgId,
|
||||||
|
Target: dashboardTarget,
|
||||||
|
Limit: 10,
|
||||||
|
}
|
||||||
|
err := sqlStore.UpdateOrgQuota(context.Background(), &orgCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("Should be able to get saved quota by org id and target", func(t *testing.T) {
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: dashboardTarget, Default: 1}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(10), query.Result.Limit)
|
||||||
|
require.Equal(t, int64(0), query.Result.Used)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Given saved user quota for org", func(t *testing.T) {
|
||||||
|
userQuotaCmd := models.UpdateUserQuotaCmd{
|
||||||
|
UserId: userId,
|
||||||
|
Target: "org_user",
|
||||||
|
Limit: 10,
|
||||||
|
}
|
||||||
|
err := sqlStore.UpdateUserQuota(context.Background(), &userQuotaCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("Should be able to get saved quota by user id and target", func(t *testing.T) {
|
||||||
|
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
|
||||||
|
err = sqlStore.GetUserQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(10), query.Result.Limit)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get default quota by user id and target", func(t *testing.T) {
|
||||||
|
query := models.GetUserQuotaByTargetQuery{UserId: 9, Target: "org_user", Default: 11}
|
||||||
|
err = sqlStore.GetUserQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(11), query.Result.Limit)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get used user quota when rows exist", func(t *testing.T) {
|
||||||
|
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 11}
|
||||||
|
err = sqlStore.GetUserQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(1), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get used user quota when no rows exist", func(t *testing.T) {
|
||||||
|
query := models.GetUserQuotaByTargetQuery{UserId: 2, Target: "org_user", Default: 11}
|
||||||
|
err = sqlStore.GetUserQuotaByTarget(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(0), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to quota list for user", func(t *testing.T) {
|
||||||
|
query := models.GetUserQuotasQuery{UserId: userId}
|
||||||
|
err = sqlStore.GetUserQuotas(context.Background(), &query)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, query.Result, 1)
|
||||||
|
require.Equal(t, int64(10), query.Result[0].Limit)
|
||||||
|
require.Equal(t, int64(1), query.Result[0].Used)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to global user quota", func(t *testing.T) {
|
||||||
|
query := models.GetGlobalQuotaByTargetQuery{Target: "user", Default: 5}
|
||||||
|
err = sqlStore.GetGlobalQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, int64(5), query.Result.Limit)
|
||||||
|
require.Equal(t, int64(1), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to global org quota", func(t *testing.T) {
|
||||||
|
query := models.GetGlobalQuotaByTargetQuery{Target: "org", Default: 5}
|
||||||
|
err = sqlStore.GetGlobalQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, int64(5), query.Result.Limit)
|
||||||
|
require.Equal(t, int64(1), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to get zero used global alert quota when table does not exist (ngalert is not enabled - default case)", func(t *testing.T) {
|
||||||
|
query := models.GetGlobalQuotaByTargetQuery{Target: "alert_rule", Default: 5}
|
||||||
|
err = sqlStore.GetGlobalQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, int64(5), query.Result.Limit)
|
||||||
|
require.Equal(t, int64(0), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should be able to global dashboard quota", func(t *testing.T) {
|
||||||
|
query := models.GetGlobalQuotaByTargetQuery{Target: dashboardTarget, Default: 5}
|
||||||
|
err = sqlStore.GetGlobalQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, int64(5), query.Result.Limit)
|
||||||
|
require.Equal(t, int64(0), query.Result.Used)
|
||||||
|
})
|
||||||
|
|
||||||
|
// related: https://github.com/grafana/grafana/issues/14342
|
||||||
|
t.Run("Should org quota updating is successful even if it called multiple time", func(t *testing.T) {
|
||||||
|
orgCmd := models.UpdateOrgQuotaCmd{
|
||||||
|
OrgId: orgId,
|
||||||
|
Target: "org_user",
|
||||||
|
Limit: 5,
|
||||||
|
}
|
||||||
|
err := sqlStore.UpdateOrgQuota(context.Background(), &orgCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(5), query.Result.Limit)
|
||||||
|
|
||||||
|
// XXX: resolution of `Updated` column is 1sec, so this makes delay
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
orgCmd = models.UpdateOrgQuotaCmd{
|
||||||
|
OrgId: orgId,
|
||||||
|
Target: "org_user",
|
||||||
|
Limit: 10,
|
||||||
|
}
|
||||||
|
err = sqlStore.UpdateOrgQuota(context.Background(), &orgCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
query = models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
|
||||||
|
err = sqlStore.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(10), query.Result.Limit)
|
||||||
|
})
|
||||||
|
|
||||||
|
// related: https://github.com/grafana/grafana/issues/14342
|
||||||
|
t.Run("Should user quota updating is successful even if it called multiple time", func(t *testing.T) {
|
||||||
|
userQuotaCmd := models.UpdateUserQuotaCmd{
|
||||||
|
UserId: userId,
|
||||||
|
Target: "org_user",
|
||||||
|
Limit: 5,
|
||||||
|
}
|
||||||
|
err := sqlStore.UpdateUserQuota(context.Background(), &userQuotaCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
|
||||||
|
err = sqlStore.GetUserQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(5), query.Result.Limit)
|
||||||
|
|
||||||
|
// XXX: resolution of `Updated` column is 1sec, so this makes delay
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
userQuotaCmd = models.UpdateUserQuotaCmd{
|
||||||
|
UserId: userId,
|
||||||
|
Target: "org_user",
|
||||||
|
Limit: 10,
|
||||||
|
}
|
||||||
|
err = sqlStore.UpdateUserQuota(context.Background(), &userQuotaCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
query = models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
|
||||||
|
err = sqlStore.GetUserQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, int64(10), query.Result.Limit)
|
||||||
|
})
|
||||||
|
}
|
@ -23,6 +23,13 @@ type Store interface {
|
|||||||
GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error
|
GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error
|
||||||
WithDbSession(ctx context.Context, callback DBTransactionFunc) error
|
WithDbSession(ctx context.Context, callback DBTransactionFunc) error
|
||||||
WithNewDbSession(ctx context.Context, callback DBTransactionFunc) error
|
WithNewDbSession(ctx context.Context, callback DBTransactionFunc) error
|
||||||
|
GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error
|
||||||
|
GetOrgQuotas(ctx context.Context, query *models.GetOrgQuotasQuery) error
|
||||||
|
UpdateOrgQuota(ctx context.Context, cmd *models.UpdateOrgQuotaCmd) error
|
||||||
|
GetUserQuotaByTarget(ctx context.Context, query *models.GetUserQuotaByTargetQuery) error
|
||||||
|
GetUserQuotas(ctx context.Context, query *models.GetUserQuotasQuery) error
|
||||||
|
UpdateUserQuota(ctx context.Context, cmd *models.UpdateUserQuotaCmd) error
|
||||||
|
GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error
|
||||||
WithTransactionalDbSession(ctx context.Context, callback DBTransactionFunc) error
|
WithTransactionalDbSession(ctx context.Context, callback DBTransactionFunc) error
|
||||||
InTransaction(ctx context.Context, fn func(ctx context.Context) error) error
|
InTransaction(ctx context.Context, fn func(ctx context.Context) error) error
|
||||||
Migrate(bool) error
|
Migrate(bool) error
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
"github.com/grafana/grafana/pkg/services/quota"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
@ -59,11 +58,6 @@ type CreateFolderCmd struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv quota.TargetSrv = "store"
|
|
||||||
QuotaTarget quota.Target = "file"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StorageService interface {
|
type StorageService interface {
|
||||||
registry.BackgroundService
|
registry.BackgroundService
|
||||||
|
|
||||||
@ -103,7 +97,7 @@ func ProvideService(
|
|||||||
features featuremgmt.FeatureToggles,
|
features featuremgmt.FeatureToggles,
|
||||||
cfg *setting.Cfg,
|
cfg *setting.Cfg,
|
||||||
quotaService quota.Service,
|
quotaService quota.Service,
|
||||||
) (StorageService, error) {
|
) StorageService {
|
||||||
settings, err := LoadStorageConfig(cfg, features)
|
settings, err := LoadStorageConfig(cfg, features)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grafanaStorageLogger.Warn("error loading storage config", "error", err)
|
grafanaStorageLogger.Warn("error loading storage config", "error", err)
|
||||||
@ -265,37 +259,7 @@ func ProvideService(
|
|||||||
s := newStandardStorageService(sql, globalRoots, initializeOrgStorages, authService, cfg)
|
s := newStandardStorageService(sql, globalRoots, initializeOrgStorages, authService, cfg)
|
||||||
s.quotaService = quotaService
|
s.quotaService = quotaService
|
||||||
s.cfg = settings
|
s.cfg = settings
|
||||||
|
return s
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: QuotaTargetSrv,
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.Usage,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(QuotaTargetSrv, QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.File)
|
|
||||||
return limits, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSystemBrandingPathFilter() filestorage.PathFilter {
|
func createSystemBrandingPathFilter() filestorage.PathFilter {
|
||||||
@ -365,32 +329,6 @@ func (s *standardStorageService) Read(ctx context.Context, user *user.SignedInUs
|
|||||||
return s.tree.GetFile(ctx, getOrgId(user), path)
|
return s.tree.GetFile(ctx, getOrgId(user), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *standardStorageService) Usage(ctx context.Context, ScopeParameters *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
|
|
||||||
err := s.sql.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
r := result{}
|
|
||||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM file WHERE path NOT LIKE '%s'", "%/")
|
|
||||||
|
|
||||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tag, err := quota.NewTag(QuotaTargetSrv, QuotaTarget, quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
u.Set(tag, r.Count)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploadRequest struct {
|
type UploadRequest struct {
|
||||||
Contents []byte
|
Contents []byte
|
||||||
Path string
|
Path string
|
||||||
@ -457,7 +395,7 @@ func (s *standardStorageService) Upload(ctx context.Context, user *user.SignedIn
|
|||||||
|
|
||||||
func (s *standardStorageService) checkFileQuota(ctx context.Context, path string) error {
|
func (s *standardStorageService) checkFileQuota(ctx context.Context, path string) error {
|
||||||
// assumes we are only uploading to the SQL database - TODO: refactor once we introduce object stores
|
// assumes we are only uploading to the SQL database - TODO: refactor once we introduce object stores
|
||||||
quotaReached, err := s.quotaService.CheckQuotaReached(ctx, QuotaTargetSrv, nil)
|
quotaReached, err := s.quotaService.CheckQuotaReached(ctx, "file", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grafanaStorageLogger.Error("failed while checking upload quota", "path", path, "error", err)
|
grafanaStorageLogger.Error("failed while checking upload quota", "path", path, "error", err)
|
||||||
return ErrUploadInternalError
|
return ErrUploadInternalError
|
||||||
|
@ -118,7 +118,7 @@ func setupUploadStore(t *testing.T, authService storageAuthService) (StorageServ
|
|||||||
store.cfg = &GlobalStorageConfig{
|
store.cfg = &GlobalStorageConfig{
|
||||||
AllowUnsanitizedSvgUpload: true,
|
AllowUnsanitizedSvgUpload: true,
|
||||||
}
|
}
|
||||||
store.quotaService = quotatest.New(false, nil)
|
store.quotaService = quotatest.NewQuotaServiceFake()
|
||||||
|
|
||||||
return store, mockStorage, storageName
|
return store, mockStorage, storageName
|
||||||
}
|
}
|
||||||
@ -297,7 +297,7 @@ func TestContentRootWithNestedStorage(t *testing.T) {
|
|||||||
store.cfg = &GlobalStorageConfig{
|
store.cfg = &GlobalStorageConfig{
|
||||||
AllowUnsanitizedSvgUpload: true,
|
AllowUnsanitizedSvgUpload: true,
|
||||||
}
|
}
|
||||||
store.quotaService = quotatest.New(false, nil)
|
store.quotaService = quotatest.NewQuotaServiceFake()
|
||||||
fileName := "file.jpg"
|
fileName := "file.jpg"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -357,8 +357,3 @@ type SearchUserFilter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FilterHandler func(params []string) (Filter, error)
|
type FilterHandler func(params []string) (Filter, error)
|
||||||
|
|
||||||
const (
|
|
||||||
QuotaTargetSrv string = "user"
|
|
||||||
QuotaTarget string = "user"
|
|
||||||
)
|
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/db"
|
"github.com/grafana/grafana/pkg/infra/db"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -38,8 +37,6 @@ type store interface {
|
|||||||
BatchDisableUsers(context.Context, *user.BatchDisableUsersCommand) error
|
BatchDisableUsers(context.Context, *user.BatchDisableUsersCommand) error
|
||||||
Disable(context.Context, *user.DisableUserCommand) error
|
Disable(context.Context, *user.DisableUserCommand) error
|
||||||
Search(context.Context, *user.SearchUsersQuery) (*user.SearchUserQueryResult, error)
|
Search(context.Context, *user.SearchUsersQuery) (*user.SearchUserQueryResult, error)
|
||||||
|
|
||||||
Count(ctx context.Context) (int64, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type sqlStore struct {
|
type sqlStore struct {
|
||||||
@ -464,22 +461,6 @@ func (ss *sqlStore) UpdatePermissions(ctx context.Context, userID int64, isAdmin
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *sqlStore) Count(ctx context.Context) (int64, error) {
|
|
||||||
type result struct {
|
|
||||||
Count int64
|
|
||||||
}
|
|
||||||
|
|
||||||
r := result{}
|
|
||||||
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
|
||||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s WHERE is_service_account=%s", ss.db.GetDialect().Quote("user"), ss.db.GetDialect().BooleanStr(false))
|
|
||||||
if _, err := sess.SQL(rawSQL).Get(&r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return r.Count, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// validateOneAdminLeft validate that there is an admin user left
|
// validateOneAdminLeft validate that there is an admin user left
|
||||||
func validateOneAdminLeft(ctx context.Context, sess *db.Session) error {
|
func validateOneAdminLeft(ctx context.Context, sess *db.Session) error {
|
||||||
count, err := sess.Where("is_admin=?", true).Count(&user.User{})
|
count, err := sess.Where("is_admin=?", true).Count(&user.User{})
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models/roletype"
|
"github.com/grafana/grafana/pkg/models/roletype"
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/services/team"
|
"github.com/grafana/grafana/pkg/services/team"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -33,44 +32,15 @@ func ProvideService(
|
|||||||
cfg *setting.Cfg,
|
cfg *setting.Cfg,
|
||||||
teamService team.Service,
|
teamService team.Service,
|
||||||
cacheService *localcache.CacheService,
|
cacheService *localcache.CacheService,
|
||||||
quotaService quota.Service,
|
) user.Service {
|
||||||
) (user.Service, error) {
|
|
||||||
store := ProvideStore(db, cfg)
|
store := ProvideStore(db, cfg)
|
||||||
s := &Service{
|
return &Service{
|
||||||
store: &store,
|
store: &store,
|
||||||
orgService: orgService,
|
orgService: orgService,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
teamService: teamService,
|
teamService: teamService,
|
||||||
cacheService: cacheService,
|
cacheService: cacheService,
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultLimits, err := readQuotaConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := quotaService.RegisterQuotaReporter("a.NewUsageReporter{
|
|
||||||
TargetSrv: quota.TargetSrv(user.QuotaTargetSrv),
|
|
||||||
DefaultLimits: defaultLimits,
|
|
||||||
Reporter: s.Usage,
|
|
||||||
}); err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Usage(ctx context.Context, _ *quota.ScopeParameters) (*quota.Map, error) {
|
|
||||||
u := "a.Map{}
|
|
||||||
if used, err := s.store.Count(ctx); err != nil {
|
|
||||||
return u, err
|
|
||||||
} else {
|
|
||||||
tag, err := quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
u.Set(tag, used)
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) {
|
func (s *Service) Create(ctx context.Context, cmd *user.CreateUserCommand) (*user.User, error) {
|
||||||
@ -334,19 +304,3 @@ func (s *Service) GetProfile(ctx context.Context, query *user.GetUserProfileQuer
|
|||||||
result, err := s.store.GetProfile(ctx, query)
|
result, err := s.store.GetProfile(ctx, query)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
|
|
||||||
limits := "a.Map{}
|
|
||||||
|
|
||||||
if cfg == nil {
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
globalQuotaTag, err := quota.NewTag(quota.TargetSrv(user.QuotaTargetSrv), quota.Target(user.QuotaTarget), quota.GlobalScope)
|
|
||||||
if err != nil {
|
|
||||||
return limits, err
|
|
||||||
}
|
|
||||||
|
|
||||||
limits.Set(globalQuotaTag, cfg.Quota.Global.User)
|
|
||||||
return limits, nil
|
|
||||||
}
|
|
||||||
|
@ -252,7 +252,3 @@ func (f *FakeUserStore) Disable(ctx context.Context, cmd *user.DisableUserComman
|
|||||||
func (f *FakeUserStore) Search(ctx context.Context, query *user.SearchUsersQuery) (*user.SearchUserQueryResult, error) {
|
func (f *FakeUserStore) Search(ctx context.Context, query *user.SearchUsersQuery) (*user.SearchUserQueryResult, error) {
|
||||||
return f.ExpectedSearchUserQueryResult, f.ExpectedError
|
return f.ExpectedSearchUserQueryResult, f.ExpectedError
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeUserStore) Count(ctx context.Context) (int64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
@ -153,6 +153,9 @@ var (
|
|||||||
LDAPAllowSignup bool
|
LDAPAllowSignup bool
|
||||||
LDAPActiveSyncEnabled bool
|
LDAPActiveSyncEnabled bool
|
||||||
|
|
||||||
|
// Quota
|
||||||
|
Quota QuotaSettings
|
||||||
|
|
||||||
// Alerting
|
// Alerting
|
||||||
AlertingEnabled *bool
|
AlertingEnabled *bool
|
||||||
ExecuteAlerts bool
|
ExecuteAlerts bool
|
||||||
@ -419,12 +422,12 @@ type Cfg struct {
|
|||||||
LDAPSkipOrgRoleSync bool
|
LDAPSkipOrgRoleSync bool
|
||||||
LDAPAllowSignup bool
|
LDAPAllowSignup bool
|
||||||
|
|
||||||
|
Quota QuotaSettings
|
||||||
|
|
||||||
DefaultTheme string
|
DefaultTheme string
|
||||||
DefaultLocale string
|
DefaultLocale string
|
||||||
HomePage string
|
HomePage string
|
||||||
|
|
||||||
Quota QuotaSettings
|
|
||||||
|
|
||||||
AutoAssignOrg bool
|
AutoAssignOrg bool
|
||||||
AutoAssignOrgId int
|
AutoAssignOrgId int
|
||||||
AutoAssignOrgRole string
|
AutoAssignOrgRole string
|
||||||
@ -1050,12 +1053,11 @@ func (cfg *Cfg) Load(args CommandLineArgs) error {
|
|||||||
cfg.readAzureSettings()
|
cfg.readAzureSettings()
|
||||||
cfg.readSessionConfig()
|
cfg.readSessionConfig()
|
||||||
cfg.readSmtpSettings()
|
cfg.readSmtpSettings()
|
||||||
|
cfg.readQuotaSettings()
|
||||||
if err := cfg.readAnnotationSettings(); err != nil {
|
if err := cfg.readAnnotationSettings(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.readQuotaSettings()
|
|
||||||
|
|
||||||
cfg.readExpressionsSettings()
|
cfg.readExpressionsSettings()
|
||||||
if err := cfg.readGrafanaEnvironmentMetrics(); err != nil {
|
if err := cfg.readGrafanaEnvironmentMetrics(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package setting
|
package setting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
type OrgQuota struct {
|
type OrgQuota struct {
|
||||||
User int64 `target:"org_user"`
|
User int64 `target:"org_user"`
|
||||||
DataSource int64 `target:"data_source"`
|
DataSource int64 `target:"data_source"`
|
||||||
@ -23,17 +27,45 @@ type GlobalQuota struct {
|
|||||||
File int64 `target:"file"`
|
File int64 `target:"file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *OrgQuota) ToMap() map[string]int64 {
|
||||||
|
return quotaToMap(*q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *UserQuota) ToMap() map[string]int64 {
|
||||||
|
return quotaToMap(*q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func quotaToMap(q interface{}) map[string]int64 {
|
||||||
|
qMap := make(map[string]int64)
|
||||||
|
typ := reflect.TypeOf(q)
|
||||||
|
val := reflect.ValueOf(q)
|
||||||
|
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
name := field.Tag.Get("target")
|
||||||
|
if name == "" {
|
||||||
|
name = field.Name
|
||||||
|
}
|
||||||
|
if name == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
value := val.Field(i)
|
||||||
|
qMap[name] = value.Int()
|
||||||
|
}
|
||||||
|
return qMap
|
||||||
|
}
|
||||||
|
|
||||||
type QuotaSettings struct {
|
type QuotaSettings struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Org OrgQuota
|
Org *OrgQuota
|
||||||
User UserQuota
|
User *UserQuota
|
||||||
Global GlobalQuota
|
Global *GlobalQuota
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Cfg) readQuotaSettings() {
|
func (cfg *Cfg) readQuotaSettings() {
|
||||||
// set global defaults.
|
// set global defaults.
|
||||||
quota := cfg.Raw.Section("quota")
|
quota := cfg.Raw.Section("quota")
|
||||||
cfg.Quota.Enabled = quota.Key("enabled").MustBool(false)
|
Quota.Enabled = quota.Key("enabled").MustBool(false)
|
||||||
|
|
||||||
var alertOrgQuota int64
|
var alertOrgQuota int64
|
||||||
var alertGlobalQuota int64
|
var alertGlobalQuota int64
|
||||||
@ -42,7 +74,7 @@ func (cfg *Cfg) readQuotaSettings() {
|
|||||||
alertGlobalQuota = quota.Key("global_alert_rule").MustInt64(-1)
|
alertGlobalQuota = quota.Key("global_alert_rule").MustInt64(-1)
|
||||||
}
|
}
|
||||||
// per ORG Limits
|
// per ORG Limits
|
||||||
cfg.Quota.Org = OrgQuota{
|
Quota.Org = &OrgQuota{
|
||||||
User: quota.Key("org_user").MustInt64(10),
|
User: quota.Key("org_user").MustInt64(10),
|
||||||
DataSource: quota.Key("org_data_source").MustInt64(10),
|
DataSource: quota.Key("org_data_source").MustInt64(10),
|
||||||
Dashboard: quota.Key("org_dashboard").MustInt64(10),
|
Dashboard: quota.Key("org_dashboard").MustInt64(10),
|
||||||
@ -51,12 +83,12 @@ func (cfg *Cfg) readQuotaSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// per User limits
|
// per User limits
|
||||||
cfg.Quota.User = UserQuota{
|
Quota.User = &UserQuota{
|
||||||
Org: quota.Key("user_org").MustInt64(10),
|
Org: quota.Key("user_org").MustInt64(10),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global Limits
|
// Global Limits
|
||||||
cfg.Quota.Global = GlobalQuota{
|
Quota.Global = &GlobalQuota{
|
||||||
User: quota.Key("global_user").MustInt64(-1),
|
User: quota.Key("global_user").MustInt64(-1),
|
||||||
Org: quota.Key("global_org").MustInt64(-1),
|
Org: quota.Key("global_org").MustInt64(-1),
|
||||||
DataSource: quota.Key("global_data_source").MustInt64(-1),
|
DataSource: quota.Key("global_data_source").MustInt64(-1),
|
||||||
@ -66,4 +98,6 @@ func (cfg *Cfg) readQuotaSettings() {
|
|||||||
File: quota.Key("global_file").MustInt64(-1),
|
File: quota.Key("global_file").MustInt64(-1),
|
||||||
AlertRule: alertGlobalQuota,
|
AlertRule: alertGlobalQuota,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg.Quota = Quota
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||||
@ -1877,8 +1878,6 @@ func TestQuota(t *testing.T) {
|
|||||||
|
|
||||||
// Create a user to make authenticated requests
|
// Create a user to make authenticated requests
|
||||||
createUser(t, store, user.CreateUserCommand{
|
createUser(t, store, user.CreateUserCommand{
|
||||||
// needs permission to update org quota
|
|
||||||
IsAdmin: true,
|
|
||||||
DefaultOrgRole: string(org.RoleEditor),
|
DefaultOrgRole: string(org.RoleEditor),
|
||||||
Password: "password",
|
Password: "password",
|
||||||
Login: "grafana",
|
Login: "grafana",
|
||||||
@ -1919,10 +1918,30 @@ func TestQuota(t *testing.T) {
|
|||||||
// check quota limits
|
// check quota limits
|
||||||
t.Run("when quota limit exceed creating new rule should fail", func(t *testing.T) {
|
t.Run("when quota limit exceed creating new rule should fail", func(t *testing.T) {
|
||||||
// get existing org quota
|
// get existing org quota
|
||||||
limit, used := apiClient.GetOrgQuotaLimits(t, 1)
|
query := models.GetOrgQuotaByTargetQuery{OrgId: 1, Target: "alert_rule"}
|
||||||
apiClient.UpdateAlertRuleOrgQuota(t, 1, used)
|
err = store.GetOrgQuotaByTarget(context.Background(), &query)
|
||||||
|
require.NoError(t, err)
|
||||||
|
used := query.Result.Used
|
||||||
|
limit := query.Result.Limit
|
||||||
|
|
||||||
|
// set org quota limit to equal used
|
||||||
|
orgCmd := models.UpdateOrgQuotaCmd{
|
||||||
|
OrgId: 1,
|
||||||
|
Target: "alert_rule",
|
||||||
|
Limit: used,
|
||||||
|
}
|
||||||
|
err := store.UpdateOrgQuota(context.Background(), &orgCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
apiClient.UpdateAlertRuleOrgQuota(t, 1, limit)
|
// reset org quota to original value
|
||||||
|
orgCmd := models.UpdateOrgQuotaCmd{
|
||||||
|
OrgId: 1,
|
||||||
|
Target: "alert_rule",
|
||||||
|
Limit: limit,
|
||||||
|
}
|
||||||
|
err := store.UpdateOrgQuota(context.Background(), &orgCmd)
|
||||||
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
// try to create an alert rule
|
// try to create an alert rule
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
|
|
||||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -203,60 +202,6 @@ func (a apiClient) CreateFolder(t *testing.T, uID string, title string) {
|
|||||||
a.ReloadCachedPermissions(t)
|
a.ReloadCachedPermissions(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a apiClient) GetOrgQuotaLimits(t *testing.T, orgID int64) (int64, int64) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
u := fmt.Sprintf("%s/api/orgs/%d/quotas", a.url, orgID)
|
|
||||||
// nolint:gosec
|
|
||||||
resp, err := http.Get(u)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer func() {
|
|
||||||
_ = resp.Body.Close()
|
|
||||||
}()
|
|
||||||
b, err := io.ReadAll(resp.Body)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
||||||
|
|
||||||
results := []quota.QuotaDTO{}
|
|
||||||
require.NoError(t, json.Unmarshal(b, &results))
|
|
||||||
|
|
||||||
var limit int64 = 0
|
|
||||||
var used int64 = 0
|
|
||||||
for _, q := range results {
|
|
||||||
if q.Target != string(ngmodels.QuotaTargetSrv) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
limit = q.Limit
|
|
||||||
used = q.Used
|
|
||||||
}
|
|
||||||
return limit, used
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a apiClient) UpdateAlertRuleOrgQuota(t *testing.T, orgID int64, limit int64) {
|
|
||||||
t.Helper()
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
enc := json.NewEncoder(&buf)
|
|
||||||
err := enc.Encode("a.UpdateQuotaCmd{
|
|
||||||
Target: "alert_rule",
|
|
||||||
Limit: limit,
|
|
||||||
OrgID: orgID,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
u := fmt.Sprintf("%s/api/orgs/%d/quotas/alert_rule", a.url, orgID)
|
|
||||||
// nolint:gosec
|
|
||||||
client := &http.Client{}
|
|
||||||
req, err := http.NewRequest(http.MethodPut, u, &buf)
|
|
||||||
require.NoError(t, err)
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer func() {
|
|
||||||
_ = resp.Body.Close()
|
|
||||||
}()
|
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a apiClient) PostRulesGroup(t *testing.T, folder string, group *apimodels.PostableRuleGroupConfig) (int, string) {
|
func (a apiClient) PostRulesGroup(t *testing.T, folder string, group *apimodels.PostableRuleGroupConfig) (int, string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
|
@ -16,14 +16,16 @@ import (
|
|||||||
datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service"
|
datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/oauthtoken"
|
"github.com/grafana/grafana/pkg/services/oauthtoken"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
|
||||||
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
"github.com/grafana/grafana/pkg/services/secrets/fakes"
|
||||||
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretskvs "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
secretsmng "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHandleRequest(t *testing.T) {
|
func TestHandleRequest(t *testing.T) {
|
||||||
|
cfg := &setting.Cfg{}
|
||||||
|
|
||||||
t.Run("Should invoke plugin manager QueryData when handling request for query", func(t *testing.T) {
|
t.Run("Should invoke plugin manager QueryData when handling request for query", func(t *testing.T) {
|
||||||
origOAuthIsOAuthPassThruEnabledFunc := oAuthIsOAuthPassThruEnabledFunc
|
origOAuthIsOAuthPassThruEnabledFunc := oAuthIsOAuthPassThruEnabledFunc
|
||||||
oAuthIsOAuthPassThruEnabledFunc = func(oAuthTokenService oauthtoken.OAuthTokenService, ds *datasources.DataSource) bool {
|
oAuthIsOAuthPassThruEnabledFunc = func(oAuthTokenService oauthtoken.OAuthTokenService, ds *datasources.DataSource) bool {
|
||||||
@ -44,10 +46,7 @@ func TestHandleRequest(t *testing.T) {
|
|||||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||||
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
secretsStore := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||||
datasourcePermissions := acmock.NewMockedPermissionsService()
|
datasourcePermissions := acmock.NewMockedPermissionsService()
|
||||||
quotaService := quotatest.New(false, nil)
|
dsService := datasourceservice.ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), datasourcePermissions)
|
||||||
dsService, err := datasourceservice.ProvideService(nil, secretsService, secretsStore, sqlStore.Cfg, featuremgmt.WithFeatures(), acmock.New(), datasourcePermissions, quotaService)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
s := ProvideService(client, nil, dsService)
|
s := ProvideService(client, nil, dsService)
|
||||||
|
|
||||||
ds := &datasources.DataSource{Id: 12, Type: "unregisteredType", JsonData: simplejson.New()}
|
ds := &datasources.DataSource{Id: 12, Type: "unregisteredType", JsonData: simplejson.New()}
|
||||||
|
Loading…
Reference in New Issue
Block a user