mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-20 22:58:44 +05:00
Adding UsageTTL, ActivationInterval to ResourceLimits
This commit is contained in:
@@ -399,9 +399,10 @@ CREATE TABLE tp_resource_limits (
|
||||
`filter_type` varchar(16) NOT NULL,
|
||||
`filter_field_name` varchar(64) NOT NULL,
|
||||
`filter_field_values` varchar(256) NOT NULL,
|
||||
`activation_time` varchar(24) NOT NULL,
|
||||
`weight` decimal(8,2) NOT NULL,
|
||||
`activation_interval` varchar(64) NOT NULL,
|
||||
`usage_ttl` varchar(32) NOT NULL,
|
||||
`limit` varchar(64) NOT NULL,
|
||||
`weight` decimal(8,2) NOT NULL,
|
||||
`action_trigger_ids` varchar(64) NOT NULL,
|
||||
`created_at` TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
|
||||
@@ -394,7 +394,8 @@ CREATE TABLE tp_resource_limits (
|
||||
"filter_type" varchar(16) NOT NULL,
|
||||
"filter_field_name" varchar(64) NOT NULL,
|
||||
"filter_field_values" varchar(256) NOT NULL,
|
||||
"activation_time" varchar(24) NOT NULL,
|
||||
"activation_interval" varchar(64) NOT NULL,
|
||||
"usage_ttl" varchar(32) NOT NULL,
|
||||
"weight" decimal(8,2) NOT NULL,
|
||||
"limit" varchar(64) NOT NULL,
|
||||
"action_trigger_ids" varchar(64) NOT NULL,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Id,FilterType,FilterFieldName,FilterFieldValues,ActivationTime,Weight,Limit,ActionTriggers
|
||||
ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,10,2,
|
||||
ResGroup1,*string_prefix,Destination,10;20,2014-07-29T15:00:00Z,10,,
|
||||
ResGroup1,*rsr_fields,,Subject(~^1.*1$);Destination(1002),,,,
|
||||
ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,10,2,
|
||||
ResGroup2,*cdr_stats,,CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20,,,,
|
||||
#Id,FilterType,FilterFieldName,FilterFieldValues,ActivationInterval,TTL,Limit,Weight,ActionTriggers
|
||||
ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,1s,2,10,
|
||||
ResGroup1,*string_prefix,Destination,10;20,,,,,
|
||||
ResGroup1,*rsr_fields,,Subject(~^1.*1$);Destination(1002),,,,,
|
||||
ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,3600s,2,10,
|
||||
ResGroup2,*cdr_stats,,CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20,,,,,
|
||||
|
||||
|
@@ -267,11 +267,11 @@ cgrates.org,mas,true,another,value,10
|
||||
`
|
||||
|
||||
resLimits = `
|
||||
#Id,FilterType,FilterFieldName,FilterFieldValues,ActivationTime,Weight,Limit,ActionTriggers
|
||||
ResGroup21,*string,HdrAccount,1001;1002,2014-07-29T15:00:00Z,10,2,
|
||||
ResGroup21,*string_prefix,HdrDestination,10;20,2014-07-29T15:00:00Z,10,,
|
||||
ResGroup21,*rsr_fields,,HdrSubject(~^1.*1$);HdrDestination(1002),,,,
|
||||
ResGroup22,*destinations,HdrDestination,DST_FS,2014-07-29T15:00:00Z,10,2,
|
||||
#Id,FilterType,FilterFieldName,FilterFieldValues,ActivationInterval,TTL,Limit,Weight,ActionTriggers
|
||||
ResGroup21,*string,HdrAccount,1001;1002,2014-07-29T15:00:00Z,1s,2,10,
|
||||
ResGroup21,*string_prefix,HdrDestination,10;20,,,,,
|
||||
ResGroup21,*rsr_fields,,HdrSubject(~^1.*1$);HdrDestination(1002),,,,,
|
||||
ResGroup22,*destinations,HdrDestination,DST_FS,2014-07-29T15:00:00Z,3600s,2,10,
|
||||
`
|
||||
)
|
||||
|
||||
|
||||
@@ -1832,11 +1832,21 @@ func (tps TpResourceLimits) AsTPResourceLimits() (result []*utils.TPResourceLimi
|
||||
rl, found := mrl[tp.Tag]
|
||||
if !found {
|
||||
rl = &utils.TPResourceLimit{
|
||||
TPid: tp.Tpid,
|
||||
ID: tp.Tag,
|
||||
ActivationTime: tp.ActivationTime,
|
||||
Weight: tp.Weight,
|
||||
Limit: tp.Limit,
|
||||
TPid: tp.Tpid,
|
||||
ID: tp.Tag,
|
||||
UsageTTL: tp.UsageTTL,
|
||||
Weight: tp.Weight,
|
||||
Limit: tp.Limit,
|
||||
}
|
||||
if len(tp.ActivationInterval) != 0 {
|
||||
tpAI := new(utils.TPActivationInterval)
|
||||
aiSplt := strings.Split(tp.ActivationInterval, utils.INFIELD_SEP)
|
||||
if len(aiSplt) == 2 {
|
||||
tpAI.ActivationTime = aiSplt[0]
|
||||
tpAI.ExpiryTime = aiSplt[1]
|
||||
} else if len(aiSplt) == 1 {
|
||||
tpAI.ActivationTime = aiSplt[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
if tp.ActionTriggerIds != "" {
|
||||
@@ -1859,56 +1869,52 @@ func (tps TpResourceLimits) AsTPResourceLimits() (result []*utils.TPResourceLimi
|
||||
return
|
||||
}
|
||||
|
||||
func APItoModelResourceLimit(rl *utils.TPResourceLimit) TpResourceLimits {
|
||||
result := TpResourceLimits{}
|
||||
for _, f := range rl.Filters {
|
||||
tp := &TpResourceLimit{
|
||||
Tpid: rl.TPid,
|
||||
Tag: rl.ID,
|
||||
ActivationTime: rl.ActivationTime,
|
||||
Weight: rl.Weight,
|
||||
Limit: rl.Limit,
|
||||
}
|
||||
for i, atid := range rl.ActionTriggerIDs {
|
||||
if i != 0 {
|
||||
tp.ActionTriggerIds = tp.ActionTriggerIds + utils.INFIELD_SEP + atid
|
||||
} else {
|
||||
tp.ActionTriggerIds = atid
|
||||
}
|
||||
}
|
||||
tp.FilterType = f.Type
|
||||
tp.FilterFieldName = f.FieldName
|
||||
for i, val := range f.Values {
|
||||
if i != 0 {
|
||||
tp.FilterFieldValues = tp.FilterFieldValues + utils.INFIELD_SEP + val
|
||||
} else {
|
||||
tp.FilterFieldValues = val
|
||||
}
|
||||
}
|
||||
result = append(result, tp)
|
||||
}
|
||||
func APItoModelResourceLimit(rl *utils.TPResourceLimit) (mdls TpResourceLimits) {
|
||||
if len(rl.Filters) == 0 {
|
||||
tp := &TpResourceLimit{
|
||||
Tpid: rl.TPid,
|
||||
Tag: rl.ID,
|
||||
ActivationTime: rl.ActivationTime,
|
||||
Weight: rl.Weight,
|
||||
Limit: rl.Limit,
|
||||
return
|
||||
}
|
||||
for i, fltr := range rl.Filters {
|
||||
mdl := &TpResourceLimit{
|
||||
Tpid: rl.TPid,
|
||||
Tag: rl.ID,
|
||||
}
|
||||
for i, atid := range rl.ActionTriggerIDs {
|
||||
if i != 0 {
|
||||
tp.ActionTriggerIds = tp.ActionTriggerIds + utils.INFIELD_SEP + atid
|
||||
} else {
|
||||
tp.ActionTriggerIds = atid
|
||||
if i == 0 {
|
||||
mdl.UsageTTL = rl.UsageTTL
|
||||
mdl.Weight = rl.Weight
|
||||
mdl.Limit = rl.Limit
|
||||
if rl.ActivationInterval != nil {
|
||||
if rl.ActivationInterval.ActivationTime != "" {
|
||||
mdl.ActivationInterval = rl.ActivationInterval.ActivationTime
|
||||
}
|
||||
if rl.ActivationInterval.ExpiryTime != "" {
|
||||
mdl.ActivationInterval += utils.INFIELD_SEP + rl.ActivationInterval.ExpiryTime
|
||||
}
|
||||
}
|
||||
for i, atid := range rl.ActionTriggerIDs {
|
||||
if i != 0 {
|
||||
mdl.ActionTriggerIds = mdl.ActionTriggerIds + utils.INFIELD_SEP + atid
|
||||
} else {
|
||||
mdl.ActionTriggerIds = atid
|
||||
}
|
||||
}
|
||||
}
|
||||
result = append(result, tp)
|
||||
mdl.FilterType = fltr.Type
|
||||
mdl.FilterFieldName = fltr.FieldName
|
||||
for i, val := range fltr.Values {
|
||||
if i != 0 {
|
||||
mdl.FilterFieldValues = mdl.FilterFieldValues + utils.INFIELD_SEP + val
|
||||
} else {
|
||||
mdl.FilterFieldValues = val
|
||||
}
|
||||
}
|
||||
mdls = append(mdls, mdl)
|
||||
}
|
||||
return result
|
||||
return
|
||||
}
|
||||
|
||||
func APItoResourceLimit(tpRL *utils.TPResourceLimit, timezone string) (rl *ResourceLimit, err error) {
|
||||
rl = &ResourceLimit{ID: tpRL.ID, Weight: tpRL.Weight, Filters: make([]*RequestFilter, len(tpRL.Filters)), Usage: make(map[string]*ResourceUsage)}
|
||||
rl = &ResourceLimit{ID: tpRL.ID, Weight: tpRL.Weight,
|
||||
Filters: make([]*RequestFilter, len(tpRL.Filters)), Usage: make(map[string]*ResourceUsage)}
|
||||
for i, f := range tpRL.Filters {
|
||||
rf := &RequestFilter{Type: f.Type, FieldName: f.FieldName, Values: f.Values}
|
||||
if err := rf.CompileValues(); err != nil {
|
||||
@@ -1916,8 +1922,10 @@ func APItoResourceLimit(tpRL *utils.TPResourceLimit, timezone string) (rl *Resou
|
||||
}
|
||||
rl.Filters[i] = rf
|
||||
}
|
||||
if rl.ActivationTime, err = utils.ParseTimeDetectLayout(tpRL.ActivationTime, timezone); err != nil {
|
||||
return nil, err
|
||||
if tpRL.ActivationInterval != nil {
|
||||
if rl.ActivationInterval, err = tpRL.ActivationInterval.AsActivationInterval(timezone); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if rl.Limit, err = strconv.ParseFloat(tpRL.Limit, 64); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -451,17 +451,18 @@ func (t TBLSMCosts) TableName() string {
|
||||
}
|
||||
|
||||
type TpResourceLimit struct {
|
||||
ID int64
|
||||
Tpid string
|
||||
Tag string `index:"0" re:""`
|
||||
FilterType string `index:"1" re:"^\*[A-Za-z].*"`
|
||||
FilterFieldName string `index:"2" re:""`
|
||||
FilterFieldValues string `index:"3" re:""`
|
||||
ActivationTime string `index:"4" re:""`
|
||||
Weight float64 `index:"5" re:"\d+\.?\d*"`
|
||||
Limit string `index:"6" re:""`
|
||||
ActionTriggerIds string `index:"7" re:""`
|
||||
CreatedAt time.Time
|
||||
ID int64
|
||||
Tpid string
|
||||
Tag string `index:"0" re:""`
|
||||
FilterType string `index:"1" re:"^\*[A-Za-z].*"`
|
||||
FilterFieldName string `index:"2" re:""`
|
||||
FilterFieldValues string `index:"3" re:""`
|
||||
ActivationInterval string `index:"4" re:""`
|
||||
UsageTTL string `index:"5" re:""`
|
||||
Limit string `index:"6" re:""`
|
||||
Weight float64 `index:"7" re:"\d+\.?\d*"`
|
||||
ActionTriggerIds string `index:"8" re:""`
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type TBLVersion struct {
|
||||
|
||||
@@ -37,17 +37,17 @@ type ResourceUsage struct {
|
||||
|
||||
// ResourceLimit represents a limit imposed for accessing a resource (eg: new calls)
|
||||
type ResourceLimit struct {
|
||||
sync.Mutex
|
||||
ID string // Identifier of this limit
|
||||
Filters []*RequestFilter // Filters for the request
|
||||
ActivationTime time.Time // Time when this limit becomes active
|
||||
ExpiryTime time.Time
|
||||
Weight float64 // Weight to sort the ResourceLimits
|
||||
Limit float64 // Limit value
|
||||
ActionTriggers ActionTriggers // Thresholds to check after changing Limit
|
||||
UsageTTL time.Duration // Expire usage after this duration
|
||||
Usage map[string]*ResourceUsage // Keep a record of usage, bounded with timestamps so we can expire too long records
|
||||
usageCounter float64 // internal counter aggregating real usage of ResourceLimit
|
||||
sync.RWMutex
|
||||
ID string // Identifier of this limit
|
||||
Filters []*RequestFilter // Filters for the request
|
||||
ActivationInterval *utils.ActivationInterval // Time when this limit becomes active and expires
|
||||
ExpiryTime time.Time
|
||||
Weight float64 // Weight to sort the ResourceLimits
|
||||
Limit float64 // Limit value
|
||||
ActionTriggers ActionTriggers // Thresholds to check after changing Limit
|
||||
UsageTTL time.Duration // Expire usage after this duration
|
||||
Usage map[string]*ResourceUsage // Keep a record of usage, bounded with timestamps so we can expire too long records
|
||||
TotalUsage float64 // internal counter aggregating real usage of ResourceLimit
|
||||
}
|
||||
|
||||
func (rl *ResourceLimit) removeExpiredUnits() {
|
||||
@@ -56,7 +56,7 @@ func (rl *ResourceLimit) removeExpiredUnits() {
|
||||
continue // not expired
|
||||
}
|
||||
delete(rl.Usage, ruID)
|
||||
rl.usageCounter -= rv.UsageUnits
|
||||
rl.TotalUsage -= rv.UsageUnits
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func (rl *ResourceLimit) UsedUnits() float64 {
|
||||
if rl.UsageTTL != 0 {
|
||||
rl.removeExpiredUnits()
|
||||
}
|
||||
return rl.usageCounter
|
||||
return rl.TotalUsage
|
||||
}
|
||||
|
||||
func (rl *ResourceLimit) RecordUsage(ru *ResourceUsage) (err error) {
|
||||
@@ -76,7 +76,7 @@ func (rl *ResourceLimit) RecordUsage(ru *ResourceUsage) (err error) {
|
||||
return fmt.Errorf("Duplicate resource usage with id: %s", ru.ID)
|
||||
}
|
||||
rl.Usage[ru.ID] = ru
|
||||
rl.usageCounter += ru.UsageUnits
|
||||
rl.TotalUsage += ru.UsageUnits
|
||||
return
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func (rl *ResourceLimit) ClearUsage(ruID string) error {
|
||||
return fmt.Errorf("Cannot find usage record with id: %s", ruID)
|
||||
}
|
||||
delete(rl.Usage, ru.ID)
|
||||
rl.usageCounter -= ru.UsageUnits
|
||||
rl.TotalUsage -= ru.UsageUnits
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -189,8 +189,7 @@ func (rls *ResourceLimiterService) matchingResourceLimitsForEvent(ev map[string]
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
if rl.ActivationTime.After(now) || (!rl.ExpiryTime.IsZero() && rl.ExpiryTime.Before(now)) { // not active
|
||||
if rl.ActivationInterval != nil && !rl.ActivationInterval.IsActiveAtTime(time.Now()) { // not active
|
||||
continue
|
||||
}
|
||||
passAllFilters := true
|
||||
@@ -223,8 +222,7 @@ func (rls *ResourceLimiterService) matchingResourceLimitsForEvent(ev map[string]
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
if rl.ActivationTime.After(now) || (!rl.ExpiryTime.IsZero() && rl.ExpiryTime.Before(now)) { // not active
|
||||
if rl.ActivationInterval != nil && !rl.ActivationInterval.IsActiveAtTime(time.Now()) { // not active
|
||||
continue
|
||||
}
|
||||
for _, fltr := range rl.Filters {
|
||||
|
||||
31
utils/activinterval.go
Normal file
31
utils/activinterval.go
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ActivationInterval struct {
|
||||
ActivationTime, ExpiryTime time.Time
|
||||
}
|
||||
|
||||
func (ai *ActivationInterval) IsActiveAtTime(atTime time.Time) bool {
|
||||
return ai.ActivationTime.Before(atTime) &&
|
||||
(ai.ExpiryTime.IsZero() || ai.ExpiryTime.After(atTime))
|
||||
}
|
||||
@@ -1262,13 +1262,14 @@ type AttrSetBalance struct {
|
||||
}
|
||||
|
||||
type TPResourceLimit struct {
|
||||
TPid string
|
||||
ID string // Identifier of this limit
|
||||
Filters []*TPRequestFilter // Filters for the request
|
||||
ActivationTime string // Time when this limit becomes active
|
||||
Weight float64 // Weight to sort the ResourceLimits
|
||||
Limit string // Limit value
|
||||
ActionTriggerIDs []string // Thresholds to check after changing Limit
|
||||
TPid string
|
||||
ID string // Identifier of this limit
|
||||
Filters []*TPRequestFilter // Filters for the request
|
||||
ActivationInterval *TPActivationInterval // Time when this limit becomes active/expires
|
||||
UsageTTL string
|
||||
Limit string // Limit value
|
||||
Weight float64 // Weight to sort the ResourceLimits
|
||||
ActionTriggerIDs []string // Thresholds to check after changing Limit
|
||||
}
|
||||
|
||||
type TPRequestFilter struct {
|
||||
@@ -1277,6 +1278,12 @@ type TPRequestFilter struct {
|
||||
Values []string // Filter definition
|
||||
}
|
||||
|
||||
// TPActivationInterval represents an activation interval for an item
|
||||
type TPActivationInterval struct {
|
||||
ActivationTime,
|
||||
ExpiryTime string
|
||||
}
|
||||
|
||||
type AttrRLsCache struct {
|
||||
LoadID string
|
||||
ResourceLimitIDs []string
|
||||
@@ -1288,6 +1295,18 @@ type AttrRLsResourceUsage struct {
|
||||
Units float64
|
||||
}
|
||||
|
||||
// AsActivationTime converts TPActivationInterval into ActivationInterval
|
||||
func (tpAI *TPActivationInterval) AsActivationInterval(timezone string) (ai *ActivationInterval, err error) {
|
||||
var at, et time.Time
|
||||
if at, err = ParseTimeDetectLayout(tpAI.ActivationTime, timezone); err != nil {
|
||||
return
|
||||
}
|
||||
if et, err = ParseTimeDetectLayout(tpAI.ExpiryTime, timezone); err != nil {
|
||||
return
|
||||
}
|
||||
return &ActivationInterval{ActivationTime: at, ExpiryTime: et}, nil
|
||||
}
|
||||
|
||||
// Attributes to send on SessionDisconnect by SMG
|
||||
type AttrDisconnectSession struct {
|
||||
EventStart map[string]interface{}
|
||||
|
||||
Reference in New Issue
Block a user