[Alerting]: Extend quota service to optionally set limits on alerts (#33283)
* Quota: Extend service to set limit on alerts * Add test for applying quota to alert rules * Apply suggestions from code review Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * Get used alert quota only if naglert is enabled * Set alert limit to zero if nglalert is not enabled Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
This commit is contained in:
co-authored by
Diana Payton
parent
985331e813
commit
540f110220
@@ -9,6 +9,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const ALERT_RULE_TARGET = "alert_rule"
|
||||
|
||||
func init() {
|
||||
bus.AddHandler("sql", GetOrgQuotaByTarget)
|
||||
bus.AddHandler("sql", GetOrgQuotas)
|
||||
@@ -35,18 +37,22 @@ func GetOrgQuotaByTarget(query *models.GetOrgQuotaByTargetQuery) error {
|
||||
quota.Limit = query.Default
|
||||
}
|
||||
|
||||
// get quota used.
|
||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", dialect.Quote(query.Target))
|
||||
resp := make([]*targetCount, 0)
|
||||
if err := x.SQL(rawSQL, query.OrgId).Find(&resp); err != nil {
|
||||
return err
|
||||
var used int64
|
||||
if query.Target != ALERT_RULE_TARGET || query.IsNgAlertEnabled {
|
||||
// get quota used.
|
||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", dialect.Quote(query.Target))
|
||||
resp := make([]*targetCount, 0)
|
||||
if err := x.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: resp[0].Count,
|
||||
Used: used,
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -78,17 +84,21 @@ func GetOrgQuotas(query *models.GetOrgQuotasQuery) error {
|
||||
|
||||
result := make([]*models.OrgQuotaDTO, len(quotas))
|
||||
for i, q := range quotas {
|
||||
// get quota used.
|
||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", dialect.Quote(q.Target))
|
||||
resp := make([]*targetCount, 0)
|
||||
if err := x.SQL(rawSQL, q.OrgId).Find(&resp); err != nil {
|
||||
return err
|
||||
var used int64
|
||||
if q.Target != ALERT_RULE_TARGET || query.IsNgAlertEnabled {
|
||||
// get quota used.
|
||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", dialect.Quote(q.Target))
|
||||
resp := make([]*targetCount, 0)
|
||||
if err := x.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: resp[0].Count,
|
||||
Used: used,
|
||||
}
|
||||
}
|
||||
query.Result = result
|
||||
@@ -138,18 +148,22 @@ func GetUserQuotaByTarget(query *models.GetUserQuotaByTargetQuery) error {
|
||||
quota.Limit = query.Default
|
||||
}
|
||||
|
||||
// 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 := x.SQL(rawSQL, query.UserId).Find(&resp); err != nil {
|
||||
return err
|
||||
var used int64
|
||||
if query.Target != ALERT_RULE_TARGET || query.IsNgAlertEnabled {
|
||||
// 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 := x.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: resp[0].Count,
|
||||
Used: used,
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -181,17 +195,21 @@ func GetUserQuotas(query *models.GetUserQuotasQuery) error {
|
||||
|
||||
result := make([]*models.UserQuotaDTO, len(quotas))
|
||||
for i, q := range quotas {
|
||||
// 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 := x.SQL(rawSQL, q.UserId).Find(&resp); err != nil {
|
||||
return err
|
||||
var used int64
|
||||
if q.Target != ALERT_RULE_TARGET || query.IsNgAlertEnabled {
|
||||
// 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 := x.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: resp[0].Count,
|
||||
Used: used,
|
||||
}
|
||||
}
|
||||
query.Result = result
|
||||
@@ -230,17 +248,22 @@ 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))
|
||||
resp := make([]*targetCount, 0)
|
||||
if err := x.SQL(rawSQL).Find(&resp); err != nil {
|
||||
return err
|
||||
var used int64
|
||||
if query.Target != ALERT_RULE_TARGET || query.IsNgAlertEnabled {
|
||||
// get quota used.
|
||||
|
||||
rawSQL := fmt.Sprintf("SELECT COUNT(*) as count from %s", dialect.Quote(query.Target))
|
||||
resp := make([]*targetCount, 0)
|
||||
if err := x.SQL(rawSQL).Find(&resp); err != nil {
|
||||
return err
|
||||
}
|
||||
used = resp[0].Count
|
||||
}
|
||||
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: resp[0].Count,
|
||||
Used: used,
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -24,6 +24,7 @@ func TestQuotaCommandsAndQueries(t *testing.T) {
|
||||
Dashboard: 5,
|
||||
DataSource: 5,
|
||||
ApiKey: 5,
|
||||
AlertRule: 5,
|
||||
},
|
||||
User: &setting.UserQuota{
|
||||
Org: 5,
|
||||
@@ -35,6 +36,7 @@ func TestQuotaCommandsAndQueries(t *testing.T) {
|
||||
DataSource: 5,
|
||||
ApiKey: 5,
|
||||
Session: 5,
|
||||
AlertRule: 5,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -87,12 +89,19 @@ func TestQuotaCommandsAndQueries(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(query.Result.Used, ShouldEqual, 0)
|
||||
})
|
||||
Convey("Should be able to get zero used org alert quota when table does not exist (ngalert is not enabled - default case)", func() {
|
||||
query := models.GetOrgQuotaByTargetQuery{OrgId: 2, Target: "alert", 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)
|
||||
So(len(query.Result), ShouldEqual, 5)
|
||||
for _, res := range query.Result {
|
||||
limit := 5 // default quota limit
|
||||
used := 0
|
||||
@@ -169,6 +178,14 @@ func TestQuotaCommandsAndQueries(t *testing.T) {
|
||||
So(query.Result.Limit, ShouldEqual, 5)
|
||||
So(query.Result.Used, ShouldEqual, 1)
|
||||
})
|
||||
Convey("Should be able to get zero used global alert quota when table does not exist (ngalert is not enabled - default case)", func() {
|
||||
query := models.GetGlobalQuotaByTargetQuery{Target: "alert_rule", Default: 5}
|
||||
err = GetGlobalQuotaByTarget(&query)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(query.Result.Limit, ShouldEqual, 5)
|
||||
So(query.Result.Used, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
// related: https://github.com/grafana/grafana/issues/14342
|
||||
Convey("Should org quota updating is successful even if it called multiple time", func() {
|
||||
|
||||
@@ -158,7 +158,6 @@ func (ss *SQLStore) ensureMainOrgAndAdminUser() error {
|
||||
|
||||
// ensure admin user
|
||||
if !ss.Cfg.DisableInitAdminCreation {
|
||||
ss.log.Debug("Creating default admin user")
|
||||
ss.log.Debug("Creating default admin user")
|
||||
if _, err := ss.createUser(ctx, sess, userCreationArgs{
|
||||
Login: ss.Cfg.AdminUser,
|
||||
|
||||
Reference in New Issue
Block a user