mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 20:24:18 -06:00
040b7d2571
Add helpers for the errutil package in favor of errutil.NewBase.
219 lines
4.3 KiB
Go
219 lines
4.3 KiB
Go
package quota
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/util/errutil"
|
|
)
|
|
|
|
var ErrBadRequest = errutil.BadRequest("quota.bad-request")
|
|
var ErrInvalidTargetSrv = errutil.BadRequest("quota.invalid-target")
|
|
var ErrInvalidScope = errutil.BadRequest("quota.invalid-scope")
|
|
var ErrFailedToGetScope = errutil.Internal("quota.failed-get-scope")
|
|
var ErrInvalidTarget = errutil.Internal("quota.invalid-target-table")
|
|
var ErrUsageFoundForTarget = errutil.NotFound("quota.missing-target-usage")
|
|
var ErrTargetSrvConflict = errutil.BadRequest("quota.target-srv-conflict")
|
|
var ErrDisabled = errutil.Forbidden("quota.disabled", errutil.WithPublicMessage("Quotas not enabled"))
|
|
var ErrInvalidTagFormat = errutil.Internal("quota.invalid-invalid-tag-format")
|
|
|
|
type ScopeParameters struct {
|
|
OrgID 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
|
|
}
|