Adding UsageTTL, ActivationInterval to ResourceLimits

This commit is contained in:
DanB
2017-05-08 22:54:43 +02:00
parent 230670e687
commit 41dba91b7a
9 changed files with 159 additions and 100 deletions

View File

@@ -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`),

View File

@@ -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,

View File

@@ -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,,,,,
1 #Id FilterType FilterFieldName FilterFieldValues ActivationTime ActivationInterval TTL Limit Weight ActionTriggers
2 ResGroup1 *string Account 1001;1002 2014-07-29T15:00:00Z 2014-07-29T15:00:00Z 1s 2 10
3 ResGroup1 *string_prefix Destination 10;20 2014-07-29T15:00:00Z 10
4 ResGroup1 *rsr_fields Subject(~^1.*1$);Destination(1002)
5 ResGroup2 *destinations Destination DST_FS 2014-07-29T15:00:00Z 2014-07-29T15:00:00Z 3600s 2 10
6 ResGroup2 *cdr_stats CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20

View File

@@ -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,
`
)

View File

@@ -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

View File

@@ -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 {

View File

@@ -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
View 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))
}

View File

@@ -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{}