diff --git a/engine/account.go b/engine/account.go index d71079607..857fe62ce 100644 --- a/engine/account.go +++ b/engine/account.go @@ -22,6 +22,7 @@ import ( "encoding/json" "errors" "fmt" + "net" "strings" "time" @@ -1171,3 +1172,57 @@ func (as *AccountSummary) Clone() (cln *AccountSummary) { } return } + +// newAccountCache constructs a DataProvider +func NewAccountDP(account *Account) (dP config.DataProvider) { + dP = &AccountDP{account: account, cache: config.NewNavigableMap(nil)} + return +} + +// AccountCache implements engine.DataProvider so we can pass it to filters +type AccountDP struct { + account *Account + cache *config.NavigableMap +} + +// String is part of engine.DataProvider interface +// when called, it will display the already parsed values out of cache +func (accDP *AccountDP) String() string { + return utils.ToJSON(accDP.account) +} + +// FieldAsInterface is part of engine.DataProvider interface +func (accDP *AccountDP) FieldAsInterface(fldPath []string) (data interface{}, err error) { + if len(fldPath) != 1 { + return nil, utils.ErrNotFound + } + if data, err = accDP.cache.FieldAsInterface(fldPath); err == nil || + err != utils.ErrNotFound { // item found in cache + return + } + err = nil // cancel previous err + //check the field in the account + accDP.cache.Set(fldPath, data, false, false) + return +} + +// FieldAsString is part of engine.DataProvider interface +func (accDP *AccountDP) FieldAsString(fldPath []string) (data string, err error) { + var valIface interface{} + valIface, err = accDP.FieldAsInterface(fldPath) + if err != nil { + return + } + return utils.IfaceAsString(valIface), nil +} + +// AsNavigableMap is part of engine.DataProvider interface +func (accDP *AccountDP) AsNavigableMap([]*config.FCTemplate) ( + nm *config.NavigableMap, err error) { + return nil, utils.ErrNotImplemented +} + +// RemoteHost is part of engine.DataProvider interface +func (accDP *AccountDP) RemoteHost() net.Addr { + return utils.LocalAddr() +} diff --git a/engine/filters.go b/engine/filters.go index 0b06e5c90..ee6dcccd0 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -16,7 +16,6 @@ along with this program. If not, see package engine import ( - "errors" "fmt" "reflect" "strings" @@ -108,6 +107,8 @@ func (fS *FilterS) connRALs(ralSChan chan rpcclient.RpcClientConnection) (err er // receives the event as DataProvider so we can accept undecoded data (ie: HttpRequest) func (fS *FilterS) Pass(tenant string, filterIDs []string, ev config.DataProvider) (pass bool, err error) { + var fieldNameDP config.DataProvider + var fieldValuesDP []config.DataProvider if len(filterIDs) == 0 { return true, nil } @@ -125,18 +126,15 @@ func (fS *FilterS) Pass(tenant string, filterIDs []string, continue } for _, fltr := range f.Rules { - // in case we have filters of type *stats,*resources or *accounts we need to send - // a rpcclient to get what we need (Metrics,Resource,Accounts) - var conn rpcclient.RpcClientConnection - switch fltr.Type { - case utils.MetaStatS, utils.MetaNotStatS: - conn = fS.statSConns - case utils.MetaResources, utils.MetaNotResources: - conn = fS.resSConns - case utils.MetaAccount: - conn = fS.ralSConns + fieldNameDP, err = fS.getFieldNameDataProvider(ev, fltr.FieldName, tenant) + if err != nil { + return pass, err } - if pass, err = fltr.Pass(ev, conn, tenant); err != nil || !pass { + fieldValuesDP, err = fS.getFieldValueDataProviders(ev, fltr.Values, tenant) + if err != nil { + return pass, err + } + if pass, err = fltr.Pass(fieldNameDP, fieldValuesDP); err != nil || !pass { return pass, err } } @@ -315,39 +313,33 @@ func (rf *FilterRule) CompileValues() (err error) { } // Pass is the method which should be used from outside. -func (fltr *FilterRule) Pass(dP config.DataProvider, - rpcClnt rpcclient.RpcClientConnection, tenant string) (result bool, err error) { +func (fltr *FilterRule) Pass(fieldNameDP config.DataProvider, + fieldValuesDP []config.DataProvider) (result bool, err error) { if fltr.negative == nil { fltr.negative = utils.BoolPointer(strings.HasPrefix(fltr.Type, utils.MetaNot)) } switch fltr.Type { case utils.MetaString, utils.MetaNotString: - result, err = fltr.passString(dP) + result, err = fltr.passString(fieldNameDP, fieldValuesDP) case utils.MetaEmpty, utils.MetaNotEmpty: - result, err = fltr.passEmpty(dP) + result, err = fltr.passEmpty(fieldNameDP) case utils.MetaExists, utils.MetaNotExists: - result, err = fltr.passExists(dP) + result, err = fltr.passExists(fieldNameDP) case utils.MetaPrefix, utils.MetaNotPrefix: - result, err = fltr.passStringPrefix(dP) + result, err = fltr.passStringPrefix(fieldNameDP, fieldValuesDP) case utils.MetaSuffix, utils.MetaNotSuffix: - result, err = fltr.passStringSuffix(dP) + result, err = fltr.passStringSuffix(fieldNameDP, fieldValuesDP) case utils.MetaTimings, utils.MetaNotTimings: - result, err = fltr.passTimings(dP) + result, err = fltr.passTimings(fieldNameDP, fieldValuesDP) case utils.MetaDestinations, utils.MetaNotDestinations: - result, err = fltr.passDestinations(dP) + result, err = fltr.passDestinations(fieldNameDP, fieldValuesDP) case utils.MetaRSR, utils.MetaNotRSR: - result, err = fltr.passRSR(dP) - case utils.MetaStatS, utils.MetaNotStatS: - result, err = fltr.passStatS(dP, rpcClnt, tenant) + result, err = fltr.passRSR(fieldValuesDP) case utils.MetaLessThan, utils.MetaLessOrEqual, utils.MetaGreaterThan, utils.MetaGreaterOrEqual: - result, err = fltr.passGreaterThan(dP) - case utils.MetaResources, utils.MetaNotResources: - result, err = fltr.passResourceS(dP, rpcClnt, tenant) + result, err = fltr.passGreaterThan(fieldNameDP, fieldValuesDP) case utils.MetaEqual, utils.MetaNotEqual: - result, err = fltr.passEqualTo(dP) - case utils.MetaAccount: - result, err = fltr.passAccountS(dP, rpcClnt, tenant) + result, err = fltr.passEqualTo(fieldNameDP, fieldValuesDP) default: err = utils.ErrPrefixNotErrNotImplemented(fltr.Type) } @@ -357,16 +349,16 @@ func (fltr *FilterRule) Pass(dP config.DataProvider, return result != *(fltr.negative), nil } -func (fltr *FilterRule) passString(dP config.DataProvider) (bool, error) { - strVal, err := config.GetDynamicString(fltr.FieldName, dP) +func (fltr *FilterRule) passString(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { + strVal, err := config.GetDynamicString(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - for _, val := range fltr.Values { - sval, err := config.GetDynamicString(val, dP) + for i, val := range fltr.Values { + sval, err := config.GetDynamicString(val, fieldValuesDP[i]) if err != nil { continue } @@ -377,8 +369,8 @@ func (fltr *FilterRule) passString(dP config.DataProvider) (bool, error) { return false, nil } -func (fltr *FilterRule) passExists(dP config.DataProvider) (bool, error) { - _, err := config.GetDynamicInterface(fltr.FieldName, dP) +func (fltr *FilterRule) passExists(fielNameDP config.DataProvider) (bool, error) { + _, err := config.GetDynamicInterface(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -388,8 +380,8 @@ func (fltr *FilterRule) passExists(dP config.DataProvider) (bool, error) { return true, nil } -func (fltr *FilterRule) passEmpty(dP config.DataProvider) (bool, error) { - val, err := config.GetDynamicInterface(fltr.FieldName, dP) +func (fltr *FilterRule) passEmpty(fielNameDP config.DataProvider) (bool, error) { + val, err := config.GetDynamicInterface(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return true, nil @@ -418,16 +410,16 @@ func (fltr *FilterRule) passEmpty(dP config.DataProvider) (bool, error) { } } -func (fltr *FilterRule) passStringPrefix(dP config.DataProvider) (bool, error) { - strVal, err := config.GetDynamicString(fltr.FieldName, dP) +func (fltr *FilterRule) passStringPrefix(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { + strVal, err := config.GetDynamicString(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - for _, prfx := range fltr.Values { - prfx, err := config.GetDynamicString(prfx, dP) + for i, prfx := range fltr.Values { + prfx, err := config.GetDynamicString(prfx, fieldValuesDP[i]) if err != nil { continue } @@ -438,16 +430,16 @@ func (fltr *FilterRule) passStringPrefix(dP config.DataProvider) (bool, error) { return false, nil } -func (fltr *FilterRule) passStringSuffix(dP config.DataProvider) (bool, error) { - strVal, err := config.GetDynamicString(fltr.FieldName, dP) +func (fltr *FilterRule) passStringSuffix(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { + strVal, err := config.GetDynamicString(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - for _, prfx := range fltr.Values { - prfx, err := config.GetDynamicString(prfx, dP) + for i, prfx := range fltr.Values { + prfx, err := config.GetDynamicString(prfx, fieldValuesDP[i]) if err != nil { continue } @@ -459,12 +451,12 @@ func (fltr *FilterRule) passStringSuffix(dP config.DataProvider) (bool, error) { } // ToDo when Timings will be available in DataDb -func (fltr *FilterRule) passTimings(dP config.DataProvider) (bool, error) { +func (fltr *FilterRule) passTimings(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { return false, utils.ErrNotImplemented } -func (fltr *FilterRule) passDestinations(dP config.DataProvider) (bool, error) { - dst, err := config.GetDynamicString(fltr.FieldName, dP) +func (fltr *FilterRule) passDestinations(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { + dst, err := config.GetDynamicString(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -474,8 +466,8 @@ func (fltr *FilterRule) passDestinations(dP config.DataProvider) (bool, error) { for _, p := range utils.SplitPrefix(dst, MIN_PREFIX_MATCH) { if destIDs, err := dm.DataDB().GetReverseDestination(p, false, utils.NonTransactional); err == nil { for _, dID := range destIDs { - for _, valDstID := range fltr.Values { - valDstID, err := config.GetDynamicString(valDstID, dP) + for i, valDstID := range fltr.Values { + valDstID, err := config.GetDynamicString(valDstID, fieldValuesDP[i]) if err != nil { continue } @@ -489,8 +481,8 @@ func (fltr *FilterRule) passDestinations(dP config.DataProvider) (bool, error) { return false, nil } -func (fltr *FilterRule) passRSR(dP config.DataProvider) (bool, error) { - _, err := fltr.rsrFields.ParseDataProviderWithInterfaces(dP, utils.NestingSep) +func (fltr *FilterRule) passRSR(fieldValuesDP []config.DataProvider) (bool, error) { + _, err := fltr.rsrFields.ParseDataProviderWithInterfaces(fieldValuesDP[0], utils.NestingSep) if err != nil { if err == utils.ErrNotFound || err == utils.ErrFilterNotPassingNoCaps { return false, nil @@ -500,48 +492,48 @@ func (fltr *FilterRule) passRSR(dP config.DataProvider) (bool, error) { return true, nil } -func (fltr *FilterRule) passStatS(dP config.DataProvider, - stats rpcclient.RpcClientConnection, tenant string) (bool, error) { - if stats == nil || reflect.ValueOf(stats).IsNil() { - return false, errors.New("Missing StatS information") - } - for _, statItem := range fltr.statItems { - statValues := make(map[string]float64) - if err := stats.Call(utils.StatSv1GetQueueFloatMetrics, - &utils.TenantIDWithArgDispatcher{TenantID: &utils.TenantID{Tenant: tenant, ID: statItem.ItemID}}, &statValues); err != nil { - return false, err - } - //convert statValues to map[string]interface{} - ifaceStatValues := make(map[string]interface{}) - for key, val := range statValues { - ifaceStatValues[key] = val - } - //convert ifaceStatValues into a NavigableMap so we can send it to passGreaterThan - nM := config.NewNavigableMap(ifaceStatValues) - //split the type in exact 2 parts - //special cases like *gt#sum#Usage - fltrType := strings.SplitN(statItem.FilterType, utils.STATS_CHAR, 2) - if len(fltrType) < 2 { - return false, errors.New(fmt.Sprintf("<%s> Invalid format for filter of type *stats", utils.FilterS)) - } - //compose the newFilter - fltr, err := NewFilterRule(fltrType[0], - utils.DynamicDataPrefix+utils.Meta+fltrType[1], []string{statItem.FilterValue}) - if err != nil { - return false, err - } - //send it to passGreaterThan - if val, err := fltr.passGreaterThan(nM); err != nil || !val { - //in case of error return false and error - //and in case of not pass return false and nil - return false, err - } - } - return true, nil -} +// func (fltr *FilterRule) passStatS(dP config.DataProvider, +// stats rpcclient.RpcClientConnection, tenant string) (bool, error) { +// if stats == nil || reflect.ValueOf(stats).IsNil() { +// return false, errors.New("Missing StatS information") +// } +// for _, statItem := range fltr.statItems { +// statValues := make(map[string]float64) +// if err := stats.Call(utils.StatSv1GetQueueFloatMetrics, +// &utils.TenantIDWithArgDispatcher{TenantID: &utils.TenantID{Tenant: tenant, ID: statItem.ItemID}}, &statValues); err != nil { +// return false, err +// } +// //convert statValues to map[string]interface{} +// ifaceStatValues := make(map[string]interface{}) +// for key, val := range statValues { +// ifaceStatValues[key] = val +// } +// //convert ifaceStatValues into a NavigableMap so we can send it to passGreaterThan +// nM := config.NewNavigableMap(ifaceStatValues) +// //split the type in exact 2 parts +// //special cases like *gt#sum#Usage +// fltrType := strings.SplitN(statItem.FilterType, utils.STATS_CHAR, 2) +// if len(fltrType) < 2 { +// return false, errors.New(fmt.Sprintf("<%s> Invalid format for filter of type *stats", utils.FilterS)) +// } +// //compose the newFilter +// fltr, err := NewFilterRule(fltrType[0], +// utils.DynamicDataPrefix+utils.Meta+fltrType[1], []string{statItem.FilterValue}) +// if err != nil { +// return false, err +// } +// //send it to passGreaterThan +// if val, err := fltr.passGreaterThan(nM); err != nil || !val { +// //in case of error return false and error +// //and in case of not pass return false and nil +// return false, err +// } +// } +// return true, nil +// } -func (fltr *FilterRule) passGreaterThan(dP config.DataProvider) (bool, error) { - fldIf, err := config.GetDynamicInterface(fltr.FieldName, dP) +func (fltr *FilterRule) passGreaterThan(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { + fldIf, err := config.GetDynamicInterface(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -556,8 +548,8 @@ func (fltr *FilterRule) passGreaterThan(dP config.DataProvider) (bool, error) { fltr.Type == utils.MetaLessThan { orEqual = true } - for _, val := range fltr.Values { - sval, err := config.GetDynamicInterface(val, dP) + for i, val := range fltr.Values { + sval, err := config.GetDynamicInterface(val, fieldValuesDP[i]) if err != nil { continue } @@ -572,73 +564,73 @@ func (fltr *FilterRule) passGreaterThan(dP config.DataProvider) (bool, error) { return false, nil } -func (fltr *FilterRule) passResourceS(dP config.DataProvider, - resourceS rpcclient.RpcClientConnection, tenant string) (bool, error) { - if resourceS == nil || reflect.ValueOf(resourceS).IsNil() { - return false, errors.New("Missing ResourceS information") - } - for _, resItem := range fltr.resourceItems { - //take total usage for resource - var reply Resource - if err := resourceS.Call(utils.ResourceSv1GetResource, - &utils.TenantID{Tenant: tenant, ID: resItem.ItemID}, &reply); err != nil { - return false, err - } - data := map[string]interface{}{ - utils.Usage: reply.totalUsage(), - } - //convert data into a NavigableMap so we can send it to passGreaterThan - nM := config.NewNavigableMap(data) - //compose the newFilter - fltr, err := NewFilterRule(resItem.FilterType, - utils.DynamicDataPrefix+utils.Usage, []string{resItem.FilterValue}) - if err != nil { - return false, err - } - // send it to passGreaterThan - if val, err := fltr.passGreaterThan(nM); err != nil || !val { - //in case of error return false and error - //and in case of not pass return false and nil - return false, err - } - } - return true, nil -} +// func (fltr *FilterRule) passResourceS(dP config.DataProvider, +// resourceS rpcclient.RpcClientConnection, tenant string) (bool, error) { +// if resourceS == nil || reflect.ValueOf(resourceS).IsNil() { +// return false, errors.New("Missing ResourceS information") +// } +// for _, resItem := range fltr.resourceItems { +// //take total usage for resource +// var reply Resource +// if err := resourceS.Call(utils.ResourceSv1GetResource, +// &utils.TenantID{Tenant: tenant, ID: resItem.ItemID}, &reply); err != nil { +// return false, err +// } +// data := map[string]interface{}{ +// utils.Usage: reply.totalUsage(), +// } +// //convert data into a NavigableMap so we can send it to passGreaterThan +// nM := config.NewNavigableMap(data) +// //compose the newFilter +// fltr, err := NewFilterRule(resItem.FilterType, +// utils.DynamicDataPrefix+utils.Usage, []string{resItem.FilterValue}) +// if err != nil { +// return false, err +// } +// // send it to passGreaterThan +// if val, err := fltr.passGreaterThan(nM); err != nil || !val { +// //in case of error return false and error +// //and in case of not pass return false and nil +// return false, err +// } +// } +// return true, nil +// } -func (fltr *FilterRule) passAccountS(dP config.DataProvider, - accountS rpcclient.RpcClientConnection, tenant string) (bool, error) { - if accountS == nil || reflect.ValueOf(accountS).IsNil() { - return false, errors.New("Missing AccountS information") - } - for _, accItem := range fltr.accountItems { - //split accItem.ItemID in two accountID and actual filter - //AccountID.BalanceMap.*monetary[0].Value - splittedString := strings.SplitN(accItem.ItemID, utils.NestingSep, 2) - accID := splittedString[0] - filterID := splittedString[1] - var reply Account - if err := accountS.Call(utils.ApierV2GetAccount, - &utils.AttrGetAccount{Tenant: tenant, Account: accID}, &reply); err != nil { - return false, err - } - //compose the newFilter - fltr, err := NewFilterRule(accItem.FilterType, - utils.DynamicDataPrefix+filterID, []string{accItem.FilterValue}) - if err != nil { - return false, err - } - dP, _ := reply.AsNavigableMap(nil) - if val, err := fltr.Pass(dP, nil, tenant); err != nil || !val { - //in case of error return false and error - //and in case of not pass return false and nil - return false, err - } - } - return true, nil -} +// func (fltr *FilterRule) passAccountS(dP config.DataProvider, +// accountS rpcclient.RpcClientConnection, tenant string) (bool, error) { +// if accountS == nil || reflect.ValueOf(accountS).IsNil() { +// return false, errors.New("Missing AccountS information") +// } +// for _, accItem := range fltr.accountItems { +// //split accItem.ItemID in two accountID and actual filter +// //AccountID.BalanceMap.*monetary[0].Value +// splittedString := strings.SplitN(accItem.ItemID, utils.NestingSep, 2) +// accID := splittedString[0] +// filterID := splittedString[1] +// var reply Account +// if err := accountS.Call(utils.ApierV2GetAccount, +// &utils.AttrGetAccount{Tenant: tenant, Account: accID}, &reply); err != nil { +// return false, err +// } +// //compose the newFilter +// fltr, err := NewFilterRule(accItem.FilterType, +// utils.DynamicDataPrefix+filterID, []string{accItem.FilterValue}) +// if err != nil { +// return false, err +// } +// dP, _ := reply.AsNavigableMap(nil) +// if val, err := fltr.Pass(dP, nil, tenant); err != nil || !val { +// //in case of error return false and error +// //and in case of not pass return false and nil +// return false, err +// } +// } +// return true, nil +// } -func (fltr *FilterRule) passEqualTo(dP config.DataProvider) (bool, error) { - fldIf, err := config.GetDynamicInterface(fltr.FieldName, dP) +func (fltr *FilterRule) passEqualTo(fielNameDP config.DataProvider, fieldValuesDP []config.DataProvider) (bool, error) { + fldIf, err := config.GetDynamicInterface(fltr.FieldName, fielNameDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -648,8 +640,8 @@ func (fltr *FilterRule) passEqualTo(dP config.DataProvider) (bool, error) { if fldStr, castStr := fldIf.(string); castStr { // attempt converting string since deserialization fails here (ie: time.Time fields) fldIf = utils.StringToInterface(fldStr) } - for _, val := range fltr.Values { - sval, err := config.GetDynamicInterface(val, dP) + for i, val := range fltr.Values { + sval, err := config.GetDynamicInterface(val, fieldValuesDP[i]) if err != nil { continue } @@ -661,3 +653,41 @@ func (fltr *FilterRule) passEqualTo(dP config.DataProvider) (bool, error) { } return false, nil } + +func (fS *FilterS) getFieldNameDataProvider(initialDP config.DataProvider, fieldName string, tenant string) (dp config.DataProvider, err error) { + switch { + case strings.HasPrefix(fieldName, utils.MetaAccounts): + //construct dataProvider from account and set it furthder + var account *Account + //extract the AccountID from fieldName + if err = fS.ralSConns.Call(utils.ApierV2GetAccount, + &utils.AttrGetAccount{Tenant: tenant, Account: "completeHereWithID"}, &account); err != nil { + return + } + case strings.HasPrefix(fieldName, utils.MetaResources): + case strings.HasPrefix(fieldName, utils.MetaStats): + default: + dp = initialDP + } + return +} + +func (fS *FilterS) getFieldValueDataProviders(initialDP config.DataProvider, values []string, tenant string) (dp []config.DataProvider, err error) { + dp = make([]config.DataProvider, len(values)) + for i, val := range values { + switch { + case strings.HasPrefix(val, utils.MetaAccounts): + var account *Account + //extract the AccountID from fieldName + if err = fS.ralSConns.Call(utils.ApierV2GetAccount, + &utils.AttrGetAccount{Tenant: tenant, Account: "completeHereWithID"}, &account); err != nil { + return + } + case strings.HasPrefix(val, utils.MetaResources): + case strings.HasPrefix(val, utils.MetaStats): + default: + dp[i] = initialDP + } + } + return +} diff --git a/engine/filters_test.go b/engine/filters_test.go index d1688d767..cace3397e 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -36,14 +36,14 @@ func TestFilterPassString(t *testing.T) { } rf := &FilterRule{Type: utils.MetaString, FieldName: "~Category", Values: []string{"call"}} - if passes, err := rf.passString(cd); err != nil { + if passes, err := rf.passString(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaString, FieldName: "~Category", Values: []string{"cal"}} - if passes, err := rf.passString(cd); err != nil { + if passes, err := rf.passString(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Filter passes") @@ -51,14 +51,14 @@ func TestFilterPassString(t *testing.T) { //not rf = &FilterRule{Type: utils.MetaNotString, FieldName: "~Category", Values: []string{"call"}} - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Filter passes") } rf = &FilterRule{Type: utils.MetaNotString, FieldName: "~Category", Values: []string{"cal"}} - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") @@ -97,7 +97,7 @@ func TestFilterPassEmpty(t *testing.T) { } //not rf = &FilterRule{Type: utils.MetaNotEmpty, FieldName: "~Category", Values: []string{}} - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{}); err != nil { t.Error(err) } else if passes { t.Error("Filter passes") @@ -136,7 +136,7 @@ func TestFilterPassExists(t *testing.T) { } //not rf = &FilterRule{Type: utils.MetaNotExists, FieldName: "~Category1", Values: []string{}} - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") @@ -155,44 +155,44 @@ func TestFilterPassStringPrefix(t *testing.T) { ExtraFields: map[string]string{"navigation": "off"}, } rf := &FilterRule{Type: utils.MetaPrefix, FieldName: "~Category", Values: []string{"call"}} - if passes, err := rf.passStringPrefix(cd); err != nil { + if passes, err := rf.passStringPrefix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaPrefix, FieldName: "~Category", Values: []string{"premium"}} - if passes, err := rf.passStringPrefix(cd); err != nil { + if passes, err := rf.passStringPrefix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passes filter") } rf = &FilterRule{Type: utils.MetaPrefix, FieldName: "~Destination", Values: []string{"+49"}} - if passes, err := rf.passStringPrefix(cd); err != nil { + if passes, err := rf.passStringPrefix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaPrefix, FieldName: "~Destination", Values: []string{"+499"}} - if passes, err := rf.passStringPrefix(cd); err != nil { + if passes, err := rf.passStringPrefix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passes filter") } rf = &FilterRule{Type: utils.MetaPrefix, FieldName: "~navigation", Values: []string{"off"}} - if passes, err := rf.passStringPrefix(cd); err != nil { + if passes, err := rf.passStringPrefix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaPrefix, FieldName: "~nonexisting", Values: []string{"off"}} - if passing, err := rf.passStringPrefix(cd); err != nil { + if passing, err := rf.passStringPrefix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passing { t.Error("Passes filter") } //not rf = &FilterRule{Type: utils.MetaNotPrefix, FieldName: "~Category", Values: []string{"premium"}} - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") @@ -211,44 +211,44 @@ func TestFilterPassStringSuffix(t *testing.T) { ExtraFields: map[string]string{"navigation": "off"}, } rf := &FilterRule{Type: utils.MetaSuffix, FieldName: "~Category", Values: []string{"call"}} - if passes, err := rf.passStringSuffix(cd); err != nil { + if passes, err := rf.passStringSuffix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaSuffix, FieldName: "~Category", Values: []string{"premium"}} - if passes, err := rf.passStringSuffix(cd); err != nil { + if passes, err := rf.passStringSuffix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passes filter") } rf = &FilterRule{Type: utils.MetaSuffix, FieldName: "~Destination", Values: []string{"963"}} - if passes, err := rf.passStringSuffix(cd); err != nil { + if passes, err := rf.passStringSuffix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaSuffix, FieldName: "~Destination", Values: []string{"4966"}} - if passes, err := rf.passStringSuffix(cd); err != nil { + if passes, err := rf.passStringSuffix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passes filter") } rf = &FilterRule{Type: utils.MetaSuffix, FieldName: "~navigation", Values: []string{"off"}} - if passes, err := rf.passStringSuffix(cd); err != nil { + if passes, err := rf.passStringSuffix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passes filter") } rf = &FilterRule{Type: utils.MetaSuffix, FieldName: "~nonexisting", Values: []string{"off"}} - if passing, err := rf.passStringSuffix(cd); err != nil { + if passing, err := rf.passStringSuffix(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passing { t.Error("Passes filter") } //not rf = &FilterRule{Type: utils.MetaNotSuffix, FieldName: "~Destination", Values: []string{"963"}} - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passes filter") @@ -270,7 +270,7 @@ func TestFilterPassRSRFields(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passRSR(cd); err != nil { + if passes, err := rf.passRSR([]config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passing") @@ -279,7 +279,7 @@ func TestFilterPassRSRFields(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passRSR(cd); err != nil { + if passes, err := rf.passRSR([]config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passing") @@ -288,7 +288,7 @@ func TestFilterPassRSRFields(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passRSR(cd); err != nil { + if passes, err := rf.passRSR([]config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passing") @@ -298,7 +298,7 @@ func TestFilterPassRSRFields(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passing") @@ -322,7 +322,7 @@ func TestFilterPassDestinations(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passDestinations(cd); err != nil { + if passes, err := rf.passDestinations(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if !passes { t.Error("Not passing") @@ -331,7 +331,7 @@ func TestFilterPassDestinations(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passDestinations(cd); err != nil { + if passes, err := rf.passDestinations(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passing") @@ -341,7 +341,7 @@ func TestFilterPassDestinations(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.Pass(cd, nil, "cgrates.org"); err != nil { + if passes, err := rf.Pass(cd, []config.DataProvider{cd}); err != nil { t.Error(err) } else if passes { t.Error("Passing") @@ -355,14 +355,14 @@ func TestFilterPassGreaterThan(t *testing.T) { } ev := config.NewNavigableMap(nil) ev.Set([]string{"ASR"}, 20, false, true) - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing") } ev = config.NewNavigableMap(nil) ev.Set([]string{"ASR"}, 40, false, true) - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if passes { t.Error("equal should not be passing") @@ -371,7 +371,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing") @@ -380,7 +380,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing") @@ -389,14 +389,14 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing") } ev = config.NewNavigableMap(nil) ev.Set([]string{"ASR"}, 20, false, true) - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if passes { t.Error("should not pass") @@ -407,7 +407,7 @@ func TestFilterPassGreaterThan(t *testing.T) { } ev = config.NewNavigableMap(nil) ev.Set([]string{"ACD"}, time.Duration(2*time.Minute), false, true) - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not pass") @@ -419,7 +419,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("passing") @@ -429,7 +429,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("passing") @@ -440,7 +440,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("passing") @@ -452,7 +452,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if passes { t.Error("passing") @@ -464,7 +464,7 @@ func TestFilterPassGreaterThan(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passGreaterThan(ev); err != nil { + if passes, err := rf.passGreaterThan(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if passes { t.Error("passing") @@ -478,14 +478,14 @@ func TestFilterpassEqualTo(t *testing.T) { } ev := config.NewNavigableMap(nil) ev.Set([]string{"ASR"}, 40.0, false, true) - if passes, err := rf.passEqualTo(ev); err != nil { + if passes, err := rf.passEqualTo(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing") } ev = config.NewNavigableMap(nil) ev.Set([]string{"ASR"}, 39, false, true) - if passes, err := rf.passEqualTo(ev); err != nil { + if passes, err := rf.passEqualTo(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if passes { t.Error("equal should not be passing") @@ -494,7 +494,7 @@ func TestFilterpassEqualTo(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.Pass(ev, nil, ""); err != nil { + if passes, err := rf.Pass(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing", passes) @@ -505,7 +505,7 @@ func TestFilterpassEqualTo(t *testing.T) { if err != nil { t.Error(err) } - if passes, err := rf.passEqualTo(ev); err != nil { + if passes, err := rf.passEqualTo(ev, []config.DataProvider{ev}); err != nil { t.Error(err) } else if !passes { t.Error("not passing") diff --git a/sessions/sessions.go b/sessions/sessions.go index cb1e5dd84..cbfee1ae3 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -987,7 +987,12 @@ func (sS *SessionS) filterSessions(sf *utils.SessionFilter, psv bool) (aSs []*Ex var err error ev := config.NewNavigableMap(me) for _, fltr := range filterRules { - if pass, err = fltr.Pass(ev, sS.statS, tenant); err != nil || !pass { + // we don't know how many values we have so we need to build the fieldValues DataProvider + fieldValuesDP := make([]config.DataProvider, len(fltr.Values)) + for i, _ := range fltr.Values { + fieldValuesDP[i] = ev + } + if pass, err = fltr.Pass(ev, fieldValuesDP); err != nil || !pass { pass = false return } @@ -1040,7 +1045,12 @@ func (sS *SessionS) filterSessionsCount(sf *utils.SessionFilter, psv bool) (coun var err error ev := config.NewNavigableMap(me) for _, fltr := range filterRules { - if pass, err = fltr.Pass(ev, sS.statS, tenant); err != nil || !pass { + // we don't know how many values we have so we need to build the fieldValues DataProvider + fieldValuesDP := make([]config.DataProvider, len(fltr.Values)) + for i, _ := range fltr.Values { + fieldValuesDP[i] = ev + } + if pass, err = fltr.Pass(ev, fieldValuesDP); err != nil || !pass { return } }