Quota: Do not count folders towards dashboard quota (#32519) (#34025)

This commit is contained in:
Marcus Efraimsson
2021-05-17 13:05:15 +02:00
committed by GitHub
parent dcfc83d6f3
commit 310ab323c8
3 changed files with 274 additions and 216 deletions
+16 -2
View File
@@ -9,6 +9,8 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
const dashboardTarget = "dashboard"
func init() {
bus.AddHandler("sql", GetOrgQuotaByTarget)
bus.AddHandler("sql", GetOrgQuotas)
@@ -36,7 +38,13 @@ func GetOrgQuotaByTarget(query *models.GetOrgQuotaByTargetQuery) error {
}
// get quota used.
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", dialect.Quote(query.Target))
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))
}
resp := make([]*targetCount, 0)
if err := x.SQL(rawSQL, query.OrgId).Find(&resp); err != nil {
return err
@@ -231,7 +239,13 @@ func UpdateUserQuota(cmd *models.UpdateUserQuotaCmd) error {
func GetGlobalQuotaByTarget(query *models.GetGlobalQuotaByTargetQuery) error {
// get quota used.
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s", dialect.Quote(query.Target))
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))
}
resp := make([]*targetCount, 0)
if err := x.SQL(rawSQL).Find(&resp); err != nil {
return err
+248 -212
View File
@@ -8,230 +8,266 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
func TestQuotaCommandsAndQueries(t *testing.T) {
Convey("Testing Quota commands & queries", t, func() {
InitTestDB(t)
userId := int64(1)
orgId := int64(0)
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,
},
User: &setting.UserQuota{
Org: 5,
},
Global: &setting.GlobalQuota{
Org: 5,
User: 5,
Dashboard: 5,
DataSource: 5,
ApiKey: 5,
Session: 5,
},
setting.Quota = setting.QuotaSettings{
Enabled: true,
Org: &setting.OrgQuota{
User: 5,
Dashboard: 5,
DataSource: 5,
ApiKey: 5,
},
User: &setting.UserQuota{
Org: 5,
},
Global: &setting.GlobalQuota{
Org: 5,
User: 5,
Dashboard: 5,
DataSource: 5,
ApiKey: 5,
Session: 5,
},
}
// 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: 1,
}
err := CreateOrg(&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 := UpdateOrgQuota(&orgCmd)
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: 1,
}
err := CreateOrg(&userCmd)
So(err, ShouldBeNil)
orgId = userCmd.Result.Id
Convey("Given saved org quota for users", func() {
orgCmd := models.UpdateOrgQuotaCmd{
OrgId: orgId,
Target: "org_user",
Limit: 10,
}
err := UpdateOrgQuota(&orgCmd)
So(err, ShouldBeNil)
Convey("Should be able to get saved quota by org id and target", func() {
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
err = GetOrgQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 10)
})
Convey("Should be able to get default quota by org id and target", func() {
query := models.GetOrgQuotaByTargetQuery{OrgId: 123, Target: "org_user", Default: 11}
err = GetOrgQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 11)
})
Convey("Should be able to get used org quota when rows exist", func() {
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 11}
err = GetOrgQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Used, ShouldEqual, 1)
})
Convey("Should be able to get used org quota when no rows exist", func() {
query := models.GetOrgQuotaByTargetQuery{OrgId: 2, Target: "org_user", Default: 11}
err = GetOrgQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Used, ShouldEqual, 0)
})
Convey("Should be able to quota list for org", func() {
query := models.GetOrgQuotasQuery{OrgId: orgId}
err = GetOrgQuotas(&query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 4)
for _, res := range query.Result {
limit := 5 // default quota limit
used := 0
if res.Target == "org_user" {
limit = 10 // customized quota limit.
used = 1
}
So(res.Limit, ShouldEqual, limit)
So(res.Used, ShouldEqual, used)
}
})
})
Convey("Given saved user quota for org", func() {
userQuotaCmd := models.UpdateUserQuotaCmd{
UserId: userId,
Target: "org_user",
Limit: 10,
}
err := UpdateUserQuota(&userQuotaCmd)
So(err, ShouldBeNil)
Convey("Should be able to get saved quota by user id and target", func() {
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
err = GetUserQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 10)
})
Convey("Should be able to get default quota by user id and target", func() {
query := models.GetUserQuotaByTargetQuery{UserId: 9, Target: "org_user", Default: 11}
err = GetUserQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 11)
})
Convey("Should be able to get used user quota when rows exist", func() {
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 11}
err = GetUserQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Used, ShouldEqual, 1)
})
Convey("Should be able to get used user quota when no rows exist", func() {
query := models.GetUserQuotaByTargetQuery{UserId: 2, Target: "org_user", Default: 11}
err = GetUserQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Used, ShouldEqual, 0)
})
Convey("Should be able to quota list for user", func() {
query := models.GetUserQuotasQuery{UserId: userId}
err = GetUserQuotas(&query)
So(err, ShouldBeNil)
So(len(query.Result), ShouldEqual, 1)
So(query.Result[0].Limit, ShouldEqual, 10)
So(query.Result[0].Used, ShouldEqual, 1)
})
})
Convey("Should be able to global user quota", func() {
query := models.GetGlobalQuotaByTargetQuery{Target: "user", Default: 5}
err = GetGlobalQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 5)
So(query.Result.Used, ShouldEqual, 0)
})
Convey("Should be able to global org quota", func() {
query := models.GetGlobalQuotaByTargetQuery{Target: "org", Default: 5}
err = GetGlobalQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 5)
So(query.Result.Used, ShouldEqual, 1)
})
// related: https://github.com/grafana/grafana/issues/14342
Convey("Should org quota updating is successful even if it called multiple time", func() {
orgCmd := models.UpdateOrgQuotaCmd{
OrgId: orgId,
Target: "org_user",
Limit: 5,
}
err := UpdateOrgQuota(&orgCmd)
So(err, ShouldBeNil)
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 = GetOrgQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 5)
// 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 = UpdateOrgQuota(&orgCmd)
So(err, ShouldBeNil)
query = models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
err = GetOrgQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 10)
require.NoError(t, err)
require.Equal(t, int64(10), query.Result.Limit)
})
// related: https://github.com/grafana/grafana/issues/14342
Convey("Should user quota updating is successful even if it called multiple time", func() {
userQuotaCmd := models.UpdateUserQuotaCmd{
UserId: userId,
Target: "org_user",
Limit: 5,
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 = GetOrgQuotaByTarget(&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 = GetOrgQuotaByTarget(&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 = GetOrgQuotaByTarget(&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 = GetOrgQuotas(&query)
require.NoError(t, err)
require.Len(t, query.Result, 4)
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)
}
err := UpdateUserQuota(&userQuotaCmd)
So(err, ShouldBeNil)
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
err = GetUserQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 5)
// 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 = UpdateUserQuota(&userQuotaCmd)
So(err, ShouldBeNil)
query = models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
err = GetUserQuotaByTarget(&query)
So(err, ShouldBeNil)
So(query.Result.Limit, ShouldEqual, 10)
})
})
t.Run("Given saved org quota for dashboards", func(t *testing.T) {
orgCmd := models.UpdateOrgQuotaCmd{
OrgId: orgId,
Target: dashboardTarget,
Limit: 10,
}
err := UpdateOrgQuota(&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 = GetOrgQuotaByTarget(&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 := UpdateUserQuota(&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 = GetUserQuotaByTarget(&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 = GetUserQuotaByTarget(&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 = GetUserQuotaByTarget(&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 = GetUserQuotaByTarget(&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 = GetUserQuotas(&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 = GetGlobalQuotaByTarget(&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 org quota", func(t *testing.T) {
query := models.GetGlobalQuotaByTargetQuery{Target: "org", Default: 5}
err = GetGlobalQuotaByTarget(&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 dashboard quota", func(t *testing.T) {
query := models.GetGlobalQuotaByTargetQuery{Target: dashboardTarget, Default: 5}
err = GetGlobalQuotaByTarget(&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 := UpdateOrgQuota(&orgCmd)
require.NoError(t, err)
query := models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
err = GetOrgQuotaByTarget(&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 = UpdateOrgQuota(&orgCmd)
require.NoError(t, err)
query = models.GetOrgQuotaByTargetQuery{OrgId: orgId, Target: "org_user", Default: 1}
err = GetOrgQuotaByTarget(&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 := UpdateUserQuota(&userQuotaCmd)
require.NoError(t, err)
query := models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
err = GetUserQuotaByTarget(&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 = UpdateUserQuota(&userQuotaCmd)
require.NoError(t, err)
query = models.GetUserQuotaByTargetQuery{UserId: userId, Target: "org_user", Default: 1}
err = GetUserQuotaByTarget(&query)
require.NoError(t, err)
require.Equal(t, int64(10), query.Result.Limit)
})
}