Commit 90231719 by woodsaj

inital backend suport for quotas. issue #321

Conflicts:
	conf/defaults.ini
	main.go
	pkg/services/sqlstore/migrations/migrations.go
parent 96af2deb
......@@ -253,4 +253,9 @@ exchange = grafana_events
enabled = false
path = /var/lib/grafana/dashboards
[quota]
user = 10
dashboard = 100
data_source = 10
endpoint = 10
collector = 10
......@@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/login"
"github.com/grafana/grafana/pkg/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/eventpublisher"
"github.com/grafana/grafana/pkg/services/notifications"
......@@ -56,6 +57,8 @@ func main() {
eventpublisher.Init()
plugins.Init()
models.InitQuotaDefaults()
if err := notifications.Init(); err != nil {
log.Fatal(3, "Notification service failed to initialize", err)
}
......
......@@ -122,6 +122,8 @@ func Register(r *macaron.Macaron) {
r.Post("/users", bind(m.AddOrgUserCommand{}), wrap(AddOrgUser))
r.Patch("/users/:userId", bind(m.UpdateOrgUserCommand{}), wrap(UpdateOrgUser))
r.Delete("/users/:userId", wrap(RemoveOrgUser))
r.Get("/quotas", wrap(GetOrgQuotas))
r.Put("/quotas/:target", bind(m.UpdateQuotaCmd{}), wrap(UpdateOrgQuota))
}, reqGrafanaAdmin)
// auth api keys
......
package api
import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
)
func GetOrgQuotas(c *middleware.Context) Response {
query := m.GetQuotasQuery{OrgId: c.ParamsInt64(":orgId")}
if err := bus.Dispatch(&query); err != nil {
return ApiError(500, "Failed to get org quotas", err)
}
return Json(200, query.Result)
}
func UpdateOrgQuota(c *middleware.Context, cmd m.UpdateQuotaCmd) Response {
cmd.OrgId = c.ParamsInt64(":orgId")
cmd.Target = m.QuotaTarget(c.Params(":target"))
if err := bus.Dispatch(&cmd); err != nil {
return ApiError(500, "Failed to update org quotas", err)
}
return ApiSuccess("Organization quota updated")
}
package models
import (
"github.com/grafana/grafana/pkg/setting"
"time"
)
type QuotaTarget string
const (
QUOTA_USER QuotaTarget = "user" //SQL table to query. ie. "select count(*) from user where org_id=?"
QUOTA_DATASOURCE QuotaTarget = "data_source"
QUOTA_DASHBOARD QuotaTarget = "dashboard"
QUOTA_ENDPOINT QuotaTarget = "endpoint"
QUOTA_COLLECTOR QuotaTarget = "collector"
)
// defaults are set from settings package.
var DefaultQuotas map[QuotaTarget]int64
func InitQuotaDefaults() {
// set global defaults.
DefaultQuotas = make(map[QuotaTarget]int64)
quota := setting.Cfg.Section("quota")
DefaultQuotas[QUOTA_USER] = quota.Key("user").MustInt64(10)
DefaultQuotas[QUOTA_DATASOURCE] = quota.Key("data_source").MustInt64(10)
DefaultQuotas[QUOTA_DASHBOARD] = quota.Key("dashboard").MustInt64(10)
DefaultQuotas[QUOTA_ENDPOINT] = quota.Key("endpoint").MustInt64(10)
DefaultQuotas[QUOTA_COLLECTOR] = quota.Key("collector").MustInt64(10)
}
type Quota struct {
Id int64
OrgId int64
Target QuotaTarget
Limit int64
Created time.Time
Updated time.Time
}
type QuotaDTO struct {
OrgId int64 `json:"org_id"`
Target QuotaTarget `json:"target"`
Limit int64 `json:"limit"`
Used int64 `json:"used"`
}
type GetQuotaByTargetQuery struct {
Target QuotaTarget
OrgId int64
Result *QuotaDTO
}
type GetQuotasQuery struct {
OrgId int64
Result []*QuotaDTO
}
type UpdateQuotaCmd struct {
Target QuotaTarget `json:"target"`
Limit int64 `json:"limit"`
OrgId int64 `json:"-"`
}
......@@ -17,6 +17,7 @@ func AddMigrations(mg *Migrator) {
addDataSourceMigration(mg)
addApiKeyMigrations(mg)
addDashboardSnapshotMigrations(mg)
addQuotaMigration(mg)
}
func addMigrationLogMigrations(mg *Migrator) {
......
package migrations
import (
. "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
)
func addQuotaMigration(mg *Migrator) {
var quotaV1 = Table{
Name: "quota",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "org_id", Type: DB_BigInt, Nullable: false},
{Name: "target", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "limit", Type: DB_BigInt, Nullable: false},
{Name: "created", Type: DB_DateTime, Nullable: false},
{Name: "updated", Type: DB_DateTime, Nullable: false},
},
Indices: []*Index{
{Cols: []string{"org_id", "target"}, Type: UniqueIndex},
},
}
mg.AddMigration("create quota table v1", NewAddTableMigration(quotaV1))
//------- indexes ------------------
addTableIndicesMigrations(mg, "v1", quotaV1)
}
package sqlstore
import (
"fmt"
"github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models"
)
func init() {
bus.AddHandler("sql", GetQuotaByTarget)
bus.AddHandler("sql", GetQuotas)
bus.AddHandler("sql", UpdateQuota)
}
type targetCount struct {
Count int64
}
func GetQuotaByTarget(query *m.GetQuotaByTargetQuery) error {
quota := m.Quota{
Target: query.Target,
OrgId: query.OrgId,
}
has, err := x.Get(quota)
if err != nil {
return err
} else if has == false {
quota.Limit = m.DefaultQuotas[query.Target]
}
//get quota used.
rawSql := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", string(query.Target))
resp := make([]*targetCount, 0)
if err := x.Sql(rawSql, query.OrgId).Find(&resp); err != nil {
return err
}
query.Result = &m.QuotaDTO{
Target: query.Target,
Limit: quota.Limit,
OrgId: query.OrgId,
Used: resp[0].Count,
}
return nil
}
func GetQuotas(query *m.GetQuotasQuery) error {
quotas := make([]*m.Quota, 0)
sess := x.Table("quota")
if err := sess.Where("org_id=?", query.OrgId).Find(&quotas); err != nil {
return err
}
seenTargets := make(map[m.QuotaTarget]bool)
for _, q := range quotas {
seenTargets[q.Target] = true
}
for t, v := range m.DefaultQuotas {
if _, ok := seenTargets[t]; !ok {
quotas = append(quotas, &m.Quota{
OrgId: query.OrgId,
Target: t,
Limit: v,
})
}
}
result := make([]*m.QuotaDTO, len(quotas))
for i, q := range quotas {
//get quota used.
rawSql := fmt.Sprintf("SELECT COUNT(*) as count from %s where org_id=?", string(q.Target))
resp := make([]*targetCount, 0)
if err := x.Sql(rawSql, q.OrgId).Find(&resp); err != nil {
return err
}
result[i] = &m.QuotaDTO{
Target: q.Target,
Limit: q.Limit,
OrgId: q.OrgId,
Used: resp[0].Count,
}
}
query.Result = result
return nil
}
func UpdateQuota(cmd *m.UpdateQuotaCmd) error {
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment