diff --git a/apier/v1/caches.go b/apier/v1/caches.go
index 923c1fd73..afda429fb 100644
--- a/apier/v1/caches.go
+++ b/apier/v1/caches.go
@@ -47,6 +47,18 @@ func (chSv1 *CacheSv1) HasItem(args *utils.ArgsGetCacheItemWithAPIOpts,
return chSv1.cacheS.V1HasItem(args, reply)
}
+// GetItem returns an Item from the cache
+func (chSv1 *CacheSv1) GetItem(args *utils.ArgsGetCacheItemWithAPIOpts,
+ reply *interface{}) error {
+ return chSv1.cacheS.V1GetItem(args, reply)
+}
+
+// GetItemWithRemote returns an Item from local or remote cache
+func (chSv1 *CacheSv1) GetItemWithRemote(args *utils.ArgsGetCacheItemWithAPIOpts,
+ reply *interface{}) error {
+ return chSv1.cacheS.V1GetItemWithRemote(args, reply)
+}
+
// GetItemExpiryTime returns the expiryTime for an item
func (chSv1 *CacheSv1) GetItemExpiryTime(args *utils.ArgsGetCacheItemWithAPIOpts,
reply *time.Time) error {
diff --git a/apier/v1/chargers_it_test.go b/apier/v1/chargers_it_test.go
index 4f725ee3a..2f5092960 100644
--- a/apier/v1/chargers_it_test.go
+++ b/apier/v1/chargers_it_test.go
@@ -104,7 +104,7 @@ var (
}
)
-//Test start here
+// Test start here
func TestChargerSIT(t *testing.T) {
sTestsChargerCache := sTestsCharger
switch *dbType {
@@ -332,7 +332,7 @@ func testChargerSProcessEvent(t *testing.T) {
},
APIOpts: map[string]interface{}{
utils.OptsContext: "simpleauth",
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: []string{"ATTR_1001_SIMPLEAUTH"},
},
},
@@ -365,7 +365,7 @@ func testChargerSProcessEvent(t *testing.T) {
},
APIOpts: map[string]interface{}{
utils.OptsContext: "simpleauth",
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: []string{"*constant:*req.RequestType:*rated;*constant:*req.Category:call"},
},
},
@@ -542,7 +542,7 @@ func testChargerSProcessWithNotFoundAttribute(t *testing.T) {
"RunID": "CustomRun",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: nil,
},
},
@@ -607,7 +607,7 @@ func testChargerSProccessEventWithProcceSRunS(t *testing.T) {
utils.RunID: "*default",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: []string{"*constant:*req.Account:1002", "*constant:*req.Account:1003"},
utils.OptsAttributesProcessRuns: 1.,
},
diff --git a/apier/v1/core.go b/apier/v1/core.go
index 7baa8a1d7..f06a51e41 100644
--- a/apier/v1/core.go
+++ b/apier/v1/core.go
@@ -96,12 +96,6 @@ func (cS *CoreSv1) StopMemoryProfiling(_ *utils.TenantWithAPIOpts, reply *string
return nil
}
-type PanicMessageArgs struct {
- Tenant string
- APIOpts map[string]interface{}
- Message string
-}
-
-func (cS *CoreSv1) Panic(args *PanicMessageArgs, _ *string) error {
- panic(args.Message)
+func (cS *CoreSv1) Panic(args *utils.PanicMessageArgs, reply *string) error {
+ return cS.cS.Panic(args, reply)
}
diff --git a/apier/v1/dispatcher.go b/apier/v1/dispatcher.go
index ae4e629bb..209578b02 100644
--- a/apier/v1/dispatcher.go
+++ b/apier/v1/dispatcher.go
@@ -73,7 +73,7 @@ type DispatcherWithAPIOpts struct {
APIOpts map[string]interface{}
}
-//SetDispatcherProfile add/update a new Dispatcher Profile
+// SetDispatcherProfile add/update a new Dispatcher Profile
func (apierSv1 *APIerSv1) SetDispatcherProfile(args *DispatcherWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.DispatcherProfile, []string{utils.ID, utils.Subsystems}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
@@ -97,7 +97,7 @@ func (apierSv1 *APIerSv1) SetDispatcherProfile(args *DispatcherWithAPIOpts, repl
return nil
}
-//RemoveDispatcherProfile remove a specific Dispatcher Profile
+// RemoveDispatcherProfile remove a specific Dispatcher Profile
func (apierSv1 *APIerSv1) RemoveDispatcherProfile(arg *utils.TenantIDWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
@@ -162,7 +162,7 @@ func (apierSv1 *APIerSv1) GetDispatcherHostIDs(tenantArg *utils.PaginatorWithTen
return nil
}
-//SetDispatcherHost add/update a new Dispatcher Host
+// SetDispatcherHost add/update a new Dispatcher Host
func (apierSv1 *APIerSv1) SetDispatcherHost(args *engine.DispatcherHostWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.DispatcherHost, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
@@ -186,7 +186,7 @@ func (apierSv1 *APIerSv1) SetDispatcherHost(args *engine.DispatcherHostWithAPIOp
return nil
}
-//RemoveDispatcherHost remove a specific Dispatcher Host
+// RemoveDispatcherHost remove a specific Dispatcher Host
func (apierSv1 *APIerSv1) RemoveDispatcherHost(arg *utils.TenantIDWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
@@ -609,6 +609,18 @@ func (dS *DispatcherCacheSv1) HasItem(args *utils.ArgsGetCacheItemWithAPIOpts,
return dS.dS.CacheSv1HasItem(args, reply)
}
+// GetItem returns an Item from the cache
+func (dS *DispatcherCacheSv1) GetItem(args *utils.ArgsGetCacheItemWithAPIOpts,
+ reply *interface{}) error {
+ return dS.dS.CacheSv1GetItem(args, reply)
+}
+
+// GetItemWithRemote returns an Item from local or remote cache
+func (dS *DispatcherCacheSv1) GetItemWithRemote(args *utils.ArgsGetCacheItemWithAPIOpts,
+ reply *interface{}) error {
+ return dS.dS.CacheSv1GetItemWithRemote(args, reply)
+}
+
// GetItemExpiryTime returns the expiryTime for an item
func (dS *DispatcherCacheSv1) GetItemExpiryTime(args *utils.ArgsGetCacheItemWithAPIOpts,
reply *time.Time) error {
@@ -888,6 +900,47 @@ func (dS *DispatcherRALsV1) Ping(args *utils.CGREvent, reply *string) error {
return dS.dS.RALsV1Ping(args, reply)
}
+// DispatcherCoreSv1 exports RPC from CoreSv1
+type DispatcherCoreSv1 struct {
+ dS *dispatchers.DispatcherService
+}
+
+func NewDispatcherCoreSv1(dps *dispatchers.DispatcherService) *DispatcherCoreSv1 {
+ return &DispatcherCoreSv1{dS: dps}
+}
+
+func (dS *DispatcherCoreSv1) Status(args *utils.TenantWithAPIOpts, reply *map[string]interface{}) error {
+ return dS.dS.CoreSv1Status(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) Ping(args *utils.CGREvent, reply *string) error {
+ return dS.dS.CoreSv1Ping(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) Sleep(args *utils.DurationArgs, reply *string) error {
+ return dS.dS.CoreSv1Sleep(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) StartCPUProfiling(args *utils.DirectoryArgs, reply *string) error {
+ return dS.dS.CoreSv1StartCPUProfiling(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) StopCPUProfiling(args *utils.TenantWithAPIOpts, reply *string) error {
+ return dS.dS.CoreSv1StopCPUProfiling(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) StartMemoryProfiling(args *utils.MemoryPrf, reply *string) error {
+ return dS.dS.CoreSv1StartMemoryProfiling(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) StopMemoryProfiling(args *utils.TenantWithAPIOpts, reply *string) error {
+ return dS.dS.CoreSv1StopMemoryProfiling(args, reply)
+}
+
+func (dS *DispatcherCoreSv1) Panic(args *utils.PanicMessageArgs, reply *string) error {
+ return dS.dS.CoreSv1Panic(args, reply)
+}
+
type DispatcherReplicatorSv1 struct {
dS *dispatchers.DispatcherService
}
diff --git a/apier/v1/dispatchersv1_it_test.go b/apier/v1/dispatchersv1_it_test.go
index 8e03f208b..1eb07d581 100644
--- a/apier/v1/dispatchersv1_it_test.go
+++ b/apier/v1/dispatchersv1_it_test.go
@@ -140,7 +140,7 @@ func testDspDspv1GetProfileForEvent(t *testing.T) {
utils.EventName: "Event1",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAny,
+ utils.MetaSubsys: utils.MetaAny,
utils.OptsDispatchersProfilesCount: 1,
},
}
@@ -189,7 +189,7 @@ func testDspDspv1GetProfileForEvent(t *testing.T) {
utils.EventName: "Event1",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAny,
+ utils.MetaSubsys: utils.MetaAny,
utils.OptsDispatchersProfilesCount: 1,
},
}
@@ -211,7 +211,7 @@ func testDspDspv1GetProfileForEventWithMethod(t *testing.T) {
ID: "testDspv2",
Event: map[string]interface{}{},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAny,
+ utils.MetaSubsys: utils.MetaAny,
"*method": utils.DispatcherSv1GetProfilesForEvent,
utils.OptsDispatchersProfilesCount: 1,
},
diff --git a/apier/v1/sessions_process_event_it_test.go b/apier/v1/sessions_process_event_it_test.go
index c261c6cb7..9302a93e4 100644
--- a/apier/v1/sessions_process_event_it_test.go
+++ b/apier/v1/sessions_process_event_it_test.go
@@ -33,8 +33,8 @@ import (
"github.com/cgrates/cgrates/utils"
)
-//Use from sessionsv1_it_test.go
-//functions insted of duplicate them here
+// Use from sessionsv1_it_test.go
+// functions insted of duplicate them here
// eg: initCfg,ResetDB,StopEngine,etc...
var sTestSessionSv1ProcessEvent = []func(t *testing.T){
testSSv1ItInitCfg,
@@ -247,7 +247,7 @@ func testSSv1ItProcessEventAuth(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsResourcesUnits: 1.,
utils.OptsResourcesUsageID: "testSSv1ItProcessEvent",
utils.OptsAttributesProfileIDs: nil,
@@ -326,7 +326,7 @@ func testSSv1ItProcessEventInitiateSession(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsResourcesUnits: 1.,
utils.OptsResourcesUsageID: "testSSv1ItProcessEvent",
utils.OptsAttributesProfileIDs: nil,
@@ -394,7 +394,7 @@ func testSSv1ItProcessEventUpdateSession(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAttributesProfileIDs: nil,
},
},
diff --git a/apier/v1/sessionsv1_it_test.go b/apier/v1/sessionsv1_it_test.go
index 569977613..6ee9a3a3a 100644
--- a/apier/v1/sessionsv1_it_test.go
+++ b/apier/v1/sessionsv1_it_test.go
@@ -283,7 +283,7 @@ func testSSv1ItAuth(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAttributesProfileIDs: nil,
utils.OptsResourcesUsageID: "TestSSv1It1",
utils.OptsResourcesUnits: 1.,
@@ -400,7 +400,7 @@ func testSSv1ItInitiateSession(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAttributesProfileIDs: nil,
utils.OptsResourcesUnits: 1.,
utils.OptsResourcesUsageID: "TestSSv1It1",
@@ -517,7 +517,7 @@ func testSSv1ItUpdateSession(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAttributesProfileIDs: nil,
},
},
@@ -664,7 +664,7 @@ func testSSv1ItProcessEvent(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAttributesProfileIDs: nil,
utils.OptsResourcesUnits: 1.,
utils.OptsResourcesUsageID: "TestSSv1It2",
@@ -848,7 +848,7 @@ func testSSv1ItForceUpdateSession(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAttributesProfileIDs: nil,
},
},
diff --git a/config/cachecfg.go b/config/cachecfg.go
index 94c9c1784..23eae0639 100644
--- a/config/cachecfg.go
+++ b/config/cachecfg.go
@@ -32,6 +32,7 @@ type CacheParamCfg struct {
TTL time.Duration
StaticTTL bool
Precache bool
+ Remote bool
Replicate bool
}
@@ -48,6 +49,9 @@ func (cParam *CacheParamCfg) loadFromJSONCfg(jsnCfg *CacheParamJsonCfg) (err err
if jsnCfg.Precache != nil {
cParam.Precache = *jsnCfg.Precache
}
+ if jsnCfg.Remote != nil {
+ cParam.Remote = *jsnCfg.Remote
+ }
if jsnCfg.Replicate != nil {
cParam.Replicate = *jsnCfg.Replicate
}
@@ -63,6 +67,7 @@ func (cParam *CacheParamCfg) AsMapInterface() (initialMP map[string]interface{})
utils.LimitCfg: cParam.Limit,
utils.StaticTTLCfg: cParam.StaticTTL,
utils.PrecacheCfg: cParam.Precache,
+ utils.RemoteCfg: cParam.Remote,
utils.ReplicateCfg: cParam.Replicate,
}
if cParam.TTL != 0 {
@@ -78,6 +83,7 @@ func (cParam CacheParamCfg) Clone() (cln *CacheParamCfg) {
TTL: cParam.TTL,
StaticTTL: cParam.StaticTTL,
Precache: cParam.Precache,
+ Remote: cParam.Remote,
Replicate: cParam.Replicate,
}
}
@@ -86,6 +92,7 @@ func (cParam CacheParamCfg) Clone() (cln *CacheParamCfg) {
type CacheCfg struct {
Partitions map[string]*CacheParamCfg
ReplicationConns []string
+ RemoteConns []string
}
func (cCfg *CacheCfg) loadFromJSONCfg(jsnCfg *CacheJsonCfg) (err error) {
@@ -110,6 +117,12 @@ func (cCfg *CacheCfg) loadFromJSONCfg(jsnCfg *CacheJsonCfg) (err error) {
cCfg.ReplicationConns[idx] = connID
}
}
+ if jsnCfg.Remote_conns != nil {
+ cCfg.RemoteConns = make([]string, len(*jsnCfg.Remote_conns))
+ for idx, connID := range *jsnCfg.Remote_conns {
+ cCfg.RemoteConns[idx] = connID
+ }
+ }
return nil
}
@@ -135,15 +148,18 @@ func (cCfg *CacheCfg) AddTmpCaches() {
}
// AsMapInterface returns the config as a map[string]interface{}
-func (cCfg *CacheCfg) AsMapInterface() (initialMP map[string]interface{}) {
- initialMP = make(map[string]interface{})
+func (cCfg *CacheCfg) AsMapInterface() (mp map[string]interface{}) {
+ mp = make(map[string]interface{})
partitions := make(map[string]interface{}, len(cCfg.Partitions))
for key, value := range cCfg.Partitions {
partitions[key] = value.AsMapInterface()
}
- initialMP[utils.PartitionsCfg] = partitions
+ mp[utils.PartitionsCfg] = partitions
if cCfg.ReplicationConns != nil {
- initialMP[utils.ReplicationConnsCfg] = cCfg.ReplicationConns
+ mp[utils.ReplicationConnsCfg] = cCfg.ReplicationConns
+ }
+ if cCfg.RemoteConns != nil {
+ mp[utils.RemoteConnsCfg] = cCfg.RemoteConns
}
return
}
@@ -157,10 +173,10 @@ func (cCfg CacheCfg) Clone() (cln *CacheCfg) {
cln.Partitions[key] = par.Clone()
}
if cCfg.ReplicationConns != nil {
- cln.ReplicationConns = make([]string, len(cCfg.ReplicationConns))
- for i, c := range cCfg.ReplicationConns {
- cln.ReplicationConns[i] = c
- }
+ cln.ReplicationConns = utils.CloneStringSlice(cCfg.ReplicationConns)
+ }
+ if cCfg.RemoteConns != nil {
+ cln.RemoteConns = utils.CloneStringSlice(cCfg.RemoteConns)
}
return
}
diff --git a/config/cachecfg_test.go b/config/cachecfg_test.go
index f4a3ec070..4ea84d583 100644
--- a/config/cachecfg_test.go
+++ b/config/cachecfg_test.go
@@ -160,13 +160,13 @@ func TestCachesCfgAsMapInterface1(t *testing.T) {
cfgJSONStr := `{
"caches":{
"partitions": {
- "*destinations": {"limit": 10000, "static_ttl": false, "precache": true, "replicate": true},
+ "*destinations": {"limit": 10000, "static_ttl": false, "precache": true, "remote": true, "replicate": true},
},
},
}`
eMap := map[string]interface{}{
utils.PartitionsCfg: map[string]interface{}{
- utils.MetaDestinations: map[string]interface{}{"limit": 10000, "static_ttl": false, "precache": true, "replicate": true},
+ utils.MetaDestinations: map[string]interface{}{"limit": 10000, "static_ttl": false, "precache": true, "remote": true, "replicate": true},
},
utils.ReplicationConnsCfg: []string{},
}
diff --git a/config/config_defaults.go b/config/config_defaults.go
index 18f1c24bf..97a63f097 100644
--- a/config/config_defaults.go
+++ b/config/config_defaults.go
@@ -260,54 +260,55 @@ const CGRATES_CFG_JSON = `
"caches":{
"partitions": {
- "*destinations": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // destination caching
- "*reverse_destinations": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // reverse destinations index caching
- "*rating_plans": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // rating plans caching
- "*rating_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // rating profiles caching
- "*actions": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // actions caching
- "*action_plans": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // action plans caching
- "*account_action_plans": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // account action plans index caching
- "*action_triggers": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // action triggers caching
- "*shared_groups": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // shared groups caching
- "*timings": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // timings caching
- "*resource_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control resource profiles caching
- "*resources": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control resources caching
- "*event_resources": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // matching resources to events
- "*statqueue_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // statqueue profiles
- "*statqueues": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // statqueues with metrics
- "*threshold_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control threshold profiles caching
- "*thresholds": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control thresholds caching
- "*filters": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control filters caching
- "*route_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control route profile caching
- "*attribute_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control attribute profile caching
- "*charger_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control charger profile caching
- "*dispatcher_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control dispatcher profile caching
- "*dispatcher_hosts": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control dispatcher hosts caching
- "*resource_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control resource filter indexes caching
- "*stat_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control stat filter indexes caching
- "*threshold_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control threshold filter indexes caching
- "*route_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control route filter indexes caching
- "*attribute_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control attribute filter indexes caching
- "*charger_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control charger filter indexes caching
- "*dispatcher_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control dispatcher filter indexes caching
- "*reverse_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control reverse filter indexes caching used only for set and remove filters
- "*dispatcher_routes": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control dispatcher routes caching
- "*dispatcher_loads": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control dispatcher load( in case of *ratio ConnParams is present)
- "*dispatchers": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // control dispatcher interface
- "*diameter_messages": {"limit": -1, "ttl": "3h", "static_ttl": false, "replicate": false}, // diameter messages caching
- "*rpc_responses": {"limit": 0, "ttl": "2s", "static_ttl": false, "replicate": false}, // RPC responses caching
- "*closed_sessions": {"limit": -1, "ttl": "10s", "static_ttl": false, "replicate": false}, // closed sessions cached for CDRs
- "*event_charges": {"limit": 0, "ttl": "10s", "static_ttl": false, "replicate": false}, // events proccessed by ChargerS
- "*cdr_ids": {"limit": -1, "ttl": "10m", "static_ttl": false, "replicate": false}, // protects CDRs against double-charging
- "*load_ids": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "replicate": false}, // control the load_ids for items
- "*rpc_connections": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // RPC connections caching
- "*uch": {"limit": -1, "ttl": "3h", "static_ttl": false, "replicate": false}, // User cache
- "*stir": {"limit": -1, "ttl": "3h", "static_ttl": false, "replicate": false}, // stirShaken cache keys
- "*apiban":{"limit": -1, "ttl": "2m", "static_ttl": false, "replicate": false},
- "*caps_events": {"limit": -1, "ttl": "", "static_ttl": false, "replicate": false}, // caps cached samples
- "*replication_hosts": {"limit": 0, "ttl": "", "static_ttl": false, "replicate": false}, // the replication hosts cache(used when replication_filtered is enbled)
+ "*destinations": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // destination caching
+ "*reverse_destinations": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // reverse destinations index caching
+ "*rating_plans": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // rating plans caching
+ "*rating_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // rating profiles caching
+ "*actions": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // actions caching
+ "*action_plans": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // action plans caching
+ "*account_action_plans": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // account action plans index caching
+ "*action_triggers": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // action triggers caching
+ "*shared_groups": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // shared groups caching
+ "*timings": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // timings caching
+ "*resource_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control resource profiles caching
+ "*resources": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control resources caching
+ "*event_resources": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // matching resources to events
+ "*statqueue_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // statqueue profiles
+ "*statqueues": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // statqueues with metrics
+ "*threshold_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control threshold profiles caching
+ "*thresholds": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control thresholds caching
+ "*filters": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control filters caching
+ "*route_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control route profile caching
+ "*attribute_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control attribute profile caching
+ "*charger_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control charger profile caching
+ "*dispatcher_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control dispatcher profile caching
+ "*dispatcher_hosts": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control dispatcher hosts caching
+ "*resource_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control resource filter indexes caching
+ "*stat_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control stat filter indexes caching
+ "*threshold_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control threshold filter indexes caching
+ "*route_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control route filter indexes caching
+ "*attribute_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control attribute filter indexes caching
+ "*charger_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control charger filter indexes caching
+ "*dispatcher_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control dispatcher filter indexes caching
+ "*reverse_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control reverse filter indexes caching used only for set and remove filters
+ "*dispatcher_routes": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control dispatcher routes caching
+ "*dispatcher_loads": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control dispatcher load( in case of *ratio ConnParams is present)
+ "*dispatchers": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control dispatcher interface
+ "*diameter_messages": {"limit": -1, "ttl": "3h", "static_ttl": false, "remote":false, "replicate": false}, // diameter messages caching
+ "*rpc_responses": {"limit": 0, "ttl": "2s", "static_ttl": false, "remote":false, "replicate": false}, // RPC responses caching
+ "*closed_sessions": {"limit": -1, "ttl": "10s", "static_ttl": false, "remote":false, "replicate": false}, // closed sessions cached for CDRs
+ "*event_charges": {"limit": 0, "ttl": "10s", "static_ttl": false, "remote":false, "replicate": false}, // events proccessed by ChargerS
+ "*cdr_ids": {"limit": -1, "ttl": "10m", "static_ttl": false, "remote":false, "replicate": false}, // protects CDRs against double-charging
+ "*load_ids": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control the load_ids for items
+ "*rpc_connections": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // RPC connections caching
+ "*uch": {"limit": -1, "ttl": "3h", "static_ttl": false, "remote":false, "replicate": false}, // User cache
+ "*stir": {"limit": -1, "ttl": "3h", "static_ttl": false, "remote":false, "replicate": false}, // stirShaken cache keys
+ "*apiban":{"limit": -1, "ttl": "2m", "static_ttl": false, "remote":false, "replicate": false},
+ "*caps_events": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // caps cached samples
+ "*replication_hosts": {"limit": 0, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // the replication hosts cache(used when replication_filtered is enbled)
},
"replication_conns": [],
+ "remote_conns": [], // the conns that are queried when the items are not found in cache
},
diff --git a/config/config_json_test.go b/config/config_json_test.go
index f06bc8c6e..e6f3157ce 100644
--- a/config/config_json_test.go
+++ b/config/config_json_test.go
@@ -88,146 +88,147 @@ func TestCacheJsonCfg(t *testing.T) {
Partitions: &map[string]*CacheParamJsonCfg{
utils.CacheDestinations: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheReverseDestinations: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheRatingPlans: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheRatingProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheActions: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheActionPlans: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheAccountActionPlans: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheActionTriggers: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheSharedGroups: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheTimings: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheResourceProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheResources: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheEventResources: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheStatQueueProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheStatQueues: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheThresholdProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheThresholds: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheFilters: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheRouteProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheAttributeProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheChargerProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDispatcherProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDispatcherHosts: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheResourceFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheStatFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheThresholdFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheRouteFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheAttributeFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheChargerFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDispatcherFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheReverseFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDispatcherRoutes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDispatcherLoads: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDispatchers: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheDiameterMessages: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer("3h"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheRPCResponses: {Limit: utils.IntPointer(0),
Ttl: utils.StringPointer("2s"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheClosedSessions: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer("10s"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheEventCharges: {Limit: utils.IntPointer(0),
Ttl: utils.StringPointer("10s"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheCDRIDs: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer("10m"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheLoadIDs: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Precache: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheRPCConnections: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheUCH: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer("3h"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheSTIR: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer("3h"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheCapsEvents: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false),
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false),
},
utils.MetaAPIBan: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer("2m"), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheReplicationHosts: {Limit: utils.IntPointer(0),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
- Replicate: utils.BoolPointer(false)},
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
},
Replication_conns: &[]string{},
+ Remote_conns: &[]string{},
}
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))
if err != nil {
diff --git a/config/config_test.go b/config/config_test.go
index 39b1564d2..7a15f711c 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -528,99 +528,100 @@ func TestCgrCfgJSONDefaultsCacheCFG(t *testing.T) {
eCacheCfg := &CacheCfg{
Partitions: map[string]*CacheParamCfg{
utils.CacheDestinations: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheReverseDestinations: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheRatingPlans: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheRatingProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheActions: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheActionPlans: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheAccountActionPlans: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheActionTriggers: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheSharedGroups: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheTimings: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheResourceProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheResources: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheEventResources: {Limit: -1,
- TTL: 0, StaticTTL: false},
+ TTL: 0, Remote: false, StaticTTL: false},
utils.CacheStatQueueProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheStatQueues: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheThresholdProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheThresholds: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheFilters: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheRouteProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheAttributeProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheChargerProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDispatcherProfiles: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDispatcherHosts: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheResourceFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheStatFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheThresholdFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheRouteFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheAttributeFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheChargerFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDispatcherFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheReverseFilterIndexes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDispatcherRoutes: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDispatcherLoads: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDispatchers: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheDiameterMessages: {Limit: -1,
- TTL: 3 * time.Hour, StaticTTL: false},
+ TTL: 3 * time.Hour, Remote: false, StaticTTL: false},
utils.CacheRPCResponses: {Limit: 0,
- TTL: 2 * time.Second, StaticTTL: false},
+ TTL: 2 * time.Second, Remote: false, StaticTTL: false},
utils.CacheClosedSessions: {Limit: -1,
- TTL: 10 * time.Second, StaticTTL: false},
+ TTL: 10 * time.Second, Remote: false, StaticTTL: false},
utils.CacheEventCharges: {Limit: 0,
- TTL: 10 * time.Second, StaticTTL: false},
+ TTL: 10 * time.Second, Remote: false, StaticTTL: false},
utils.CacheCDRIDs: {Limit: -1,
- TTL: 10 * time.Minute, StaticTTL: false},
+ TTL: 10 * time.Minute, Remote: false, StaticTTL: false},
utils.CacheLoadIDs: {Limit: -1,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
utils.CacheRPCConnections: {Limit: -1,
- TTL: 0, StaticTTL: false},
+ TTL: 0, Remote: false, StaticTTL: false},
utils.CacheUCH: {Limit: -1,
- TTL: 3 * time.Hour, StaticTTL: false},
+ TTL: 3 * time.Hour, Remote: false, StaticTTL: false},
utils.CacheSTIR: {Limit: -1,
- TTL: 3 * time.Hour, StaticTTL: false},
+ TTL: 3 * time.Hour, Remote: false, StaticTTL: false},
utils.CacheCapsEvents: {Limit: -1},
utils.MetaAPIBan: {Limit: -1,
- TTL: 2 * time.Minute, StaticTTL: false, Precache: false},
+ TTL: 2 * time.Minute, Remote: false, StaticTTL: false, Precache: false},
utils.CacheReplicationHosts: {Limit: 0,
- TTL: 0, StaticTTL: false, Precache: false},
+ TTL: 0, Remote: false, StaticTTL: false, Precache: false},
},
ReplicationConns: []string{},
+ RemoteConns: []string{},
}
if !reflect.DeepEqual(eCacheCfg, cgrCfg.CacheCfg()) {
@@ -3679,6 +3680,7 @@ func TestV1GetConfigCache(t *testing.T) {
expected := map[string]interface{}{
CACHE_JSN: map[string]interface{}{
utils.PartitionsCfg: map[string]interface{}{},
+ utils.RemoteConnsCfg: []string{},
utils.ReplicationConnsCfg: []string{},
},
}
@@ -4379,6 +4381,7 @@ func TestV1GetConfigSectionEES(t *testing.T) {
utils.LimitCfg: -1,
utils.PrecacheCfg: false,
utils.ReplicateCfg: false,
+ utils.RemoteCfg: false,
utils.TTLCfg: "5s",
utils.StaticTTLCfg: false,
},
@@ -4791,7 +4794,7 @@ func TestV1GetConfigAsJSONTls(t *testing.T) {
func TestV1GetConfigAsJSONTCache(t *testing.T) {
var reply string
- expected := `{"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"replication_conns":[]}}`
+ expected := `{"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*shared_groups":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]}}`
cfgCgr := NewDefaultCGRConfig()
if err := cfgCgr.V1GetConfigAsJSON(&SectionWithAPIOpts{Section: CACHE_JSN}, &reply); err != nil {
t.Error(err)
@@ -5090,7 +5093,7 @@ func TestV1GetConfigAsJSONApierS(t *testing.T) {
func TestV1GetConfigAsJSONCfgEES(t *testing.T) {
var reply string
- expected := `{"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]}}`
+ expected := `{"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]}}`
cgrCfg := NewDefaultCGRConfig()
if err := cgrCfg.V1GetConfigAsJSON(&SectionWithAPIOpts{Section: EEsJson}, &reply); err != nil {
t.Error(err)
@@ -5270,7 +5273,7 @@ func TestV1GetConfigAsJSONAllConfig(t *testing.T) {
}`
var reply string
cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSON)
- expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*processRuns":1,"*profileIDs":[],"*profileIgnoreFilters":false,"*profileRuns":0},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*shared_groups":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listen":"127.0.0.1:2053","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime","xmlRootPath":""},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"MaxReconnectInterval","tag":"MaxReconnectInterval","type":"*variable","value":"~*req.6"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.7"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.8"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.9"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.10"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.11"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{"mongoQueryTimeout":"0s","mysqlDSNParams":null,"mysqlLocation":"","pgSSLMode":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":0,"sqlMaxOpenConns":0},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"mysql","out_stordb_user":"cgrates","users_filters":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*context":"*routes","*ignoreErrors":false,"*maxCost":""},"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*session_costs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_account_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_attributes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_chargers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destination_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_routes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_stats":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}`
+ expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"apiers":{"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false,"scheduler_conns":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*processRuns":1,"*profileIDs":[],"*profileIgnoreFilters":false,"*profileRuns":0},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*dispatcher_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_loads":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*dispatchers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*shared_groups":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":[],"rals_conns":[],"scheduler_conns":[],"session_cost_retries":5,"stats_conns":[],"store_cdrs":true,"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","concurrent_requests":-1,"dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listen":"127.0.0.1:2053","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"concurrent_requests":0,"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime","xmlRootPath":""},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","run_delay":"0","source_path":"/var/spool/cgrates/ers/in","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"apiers_conns":[],"resources_conns":[],"stats_conns":[]},"freeswitch_agent":{"create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","locking_timeout":"0","log_level":6,"logger":"*syslog","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","poster_attempts":3,"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"rsr_separator":";","tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTlsVerify":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","scheduler_conns":["*localhost"],"tpid":""},"loaders":[{"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"AttributeFilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Path","tag":"Path","type":"*variable","value":"~*req.6"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.7"},{"path":"Value","tag":"Value","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.10"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Values","tag":"Values","type":"*variable","value":"~*req.4"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.5"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.10"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.6"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.7"},{"path":"MetricFilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.11"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.8"},{"path":"ActionIDs","tag":"ActionIDs","type":"*variable","value":"~*req.9"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.10"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.4"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.5"},{"path":"RouteID","tag":"RouteID","type":"*variable","value":"~*req.6"},{"path":"RouteFilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.7"},{"path":"RouteAccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.8"},{"path":"RouteRatingPlanIDs","tag":"RouteRatingPlanIDs","type":"*variable","value":"~*req.9"},{"path":"RouteResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.10"},{"path":"RouteStatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.11"},{"path":"RouteWeight","tag":"RouteWeight","type":"*variable","value":"~*req.12"},{"path":"RouteBlocker","tag":"RouteBlocker","type":"*variable","value":"~*req.13"},{"path":"RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.14"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.3"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.4"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.5"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Contexts","tag":"Contexts","type":"*variable","value":"~*req.2"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.3"},{"path":"ActivationInterval","tag":"ActivationInterval","type":"*variable","value":"~*req.4"},{"path":"Strategy","tag":"Strategy","type":"*variable","value":"~*req.5"},{"path":"StrategyParameters","tag":"StrategyParameters","type":"*variable","value":"~*req.6"},{"path":"ConnID","tag":"ConnID","type":"*variable","value":"~*req.7"},{"path":"ConnFilterIDs","tag":"ConnFilterIDs","type":"*variable","value":"~*req.8"},{"path":"ConnWeight","tag":"ConnWeight","type":"*variable","value":"~*req.9"},{"path":"ConnBlocker","tag":"ConnBlocker","type":"*variable","value":"~*req.10"},{"path":"ConnParameters","tag":"ConnParameters","type":"*variable","value":"~*req.11"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherProfiles.csv","flags":null,"type":"*dispatchers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Address","tag":"Address","type":"*variable","value":"~*req.2"},{"path":"Transport","tag":"Transport","type":"*variable","value":"~*req.3"},{"path":"ConnectAttempts","tag":"ConnectAttempts","type":"*variable","value":"~*req.4"},{"path":"Reconnects","tag":"Reconnects","type":"*variable","value":"~*req.5"},{"path":"MaxReconnectInterval","tag":"MaxReconnectInterval","type":"*variable","value":"~*req.6"},{"path":"ConnectTimeout","tag":"ConnectTimeout","type":"*variable","value":"~*req.7"},{"path":"ReplyTimeout","tag":"ReplyTimeout","type":"*variable","value":"~*req.8"},{"path":"TLS","tag":"TLS","type":"*variable","value":"~*req.9"},{"path":"ClientKey","tag":"ClientKey","type":"*variable","value":"~*req.10"},{"path":"ClientCertificate","tag":"ClientCertificate","type":"*variable","value":"~*req.11"},{"path":"CaCertificate","tag":"CaCertificate","type":"*variable","value":"~*req.12"}],"file_name":"DispatcherHosts.csv","flags":null,"type":"*dispatcher_hosts"}],"dry_run":false,"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"mailer":{"auth_password":"CGRateS.org","auth_user":"cgrates","from_address":"cgr-mailer@localhost.localdomain","server":"localhost"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"redis","out_datadb_user":"cgrates","out_stordb_host":"127.0.0.1","out_stordb_name":"cgrates","out_stordb_opts":{"mongoQueryTimeout":"0s","mysqlDSNParams":null,"mysqlLocation":"","pgSSLMode":"","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":0,"sqlMaxOpenConns":0},"out_stordb_password":"","out_stordb_port":"3306","out_stordb_type":"mysql","out_stordb_user":"cgrates","users_filters":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"stats_conns":[],"thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"attributes_conns":[],"default_ratio":1,"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*context":"*routes","*ignoreErrors":false,"*maxCost":""},"prefix_indexed_fields":[],"rals_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"schedulers":{"cdrs_conns":[],"dynaprepaid_actionplans":[],"enabled":false,"filters":[],"stats_conns":[],"thresholds_conns":[]},"sessions":{"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"debit_interval":"0","default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","rals_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"scheduler_conns":[],"session_indexes":[],"session_ttl":"0","stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":1000000000,"sessions_conns":["*internal"],"timezone":""},"stats":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"","db_port":3306,"db_type":"*mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*session_costs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_account_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_action_triggers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_attributes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_chargers":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destination_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_destinations":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_hosts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_dispatcher_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rates":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_plans":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rating_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_routes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_shared_groups":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_stats":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_timings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","sqlConnMaxLifetime":"0s","sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*req.CGRID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"enabled":false,"indexed_selects":true,"nested_fields":false,"opts":{"*profileIDs":[],"*profileIgnoreFilters":false},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4}}`
if err != nil {
t.Fatal(err)
}
diff --git a/config/eescfg_test.go b/config/eescfg_test.go
index 80fd0e620..d4aa291fe 100644
--- a/config/eescfg_test.go
+++ b/config/eescfg_test.go
@@ -639,6 +639,7 @@ func TestEEsCfgAsMapInterface(t *testing.T) {
utils.LimitCfg: -2,
utils.PrecacheCfg: false,
utils.ReplicateCfg: false,
+ utils.RemoteCfg: false,
utils.TTLCfg: "1s",
utils.StaticTTLCfg: false,
},
diff --git a/config/libconfig_json.go b/config/libconfig_json.go
index 6a927c882..b5e5ff819 100644
--- a/config/libconfig_json.go
+++ b/config/libconfig_json.go
@@ -462,12 +462,14 @@ type CacheParamJsonCfg struct {
Ttl *string
Static_ttl *bool
Precache *bool
+ Remote *bool
Replicate *bool
}
type CacheJsonCfg struct {
Partitions *map[string]*CacheParamJsonCfg
Replication_conns *[]string
+ Remote_conns *[]string
}
// SM-Kamailio config section
diff --git a/cores/core.go b/cores/core.go
index 86a59dc61..56263ea40 100644
--- a/cores/core.go
+++ b/cores/core.go
@@ -202,3 +202,8 @@ func (cS *CoreService) StopMemoryProfiling() (err error) {
cS.StopChanMemProf()
return
}
+
+// Panic is used print the Message sent as a panic
+func (cS *CoreService) Panic(args *utils.PanicMessageArgs, _ *string) error {
+ panic(args.Message)
+}
diff --git a/data/conf/samples/dispatcher_opts/cgrates.json b/data/conf/samples/dispatcher_opts/cgrates.json
new file mode 100644
index 000000000..65debab34
--- /dev/null
+++ b/data/conf/samples/dispatcher_opts/cgrates.json
@@ -0,0 +1,52 @@
+{
+
+ "general": {
+ "node_id": "DispatcherOpts",
+ "log_level": 7
+ },
+
+ "listen": {
+ "rpc_json": ":2012",
+ "rpc_gob": ":2013",
+ "http": ":2080"
+ },
+
+ "data_db": {
+ "db_type": "redis",
+ "db_port": 6379,
+ "db_name": "10"
+ },
+
+ "stor_db": {
+ "db_password": "CGRateS.org"
+ },
+
+ "attributes": {
+ "enabled": true
+ },
+
+
+ "dispatchers":{
+ "enabled": true
+ },
+
+ "caches":{
+ "remote_conns": ["gob_cache"]
+ },
+
+ "rpc_conns": {
+ "gob_cache": {
+ "strategy": "*first",
+ "conns": [
+ {"address": "127.0.0.1:2013", "transport":"*gob"}
+ ]
+ }
+ },
+
+
+ "apiers": {
+ "enabled": true
+ }
+
+
+}
\ No newline at end of file
diff --git a/data/conf/samples/dispatcher_opts_apier/cgrates.json b/data/conf/samples/dispatcher_opts_apier/cgrates.json
new file mode 100644
index 000000000..aebba42fb
--- /dev/null
+++ b/data/conf/samples/dispatcher_opts_apier/cgrates.json
@@ -0,0 +1,51 @@
+{
+
+ "general": {
+ "node_id": "DispatcherOpts_APIer",
+ "log_level": 7
+ },
+
+
+ "listen": {
+ "rpc_json": ":4012",
+ "rpc_gob": ":4013",
+ "http": ":4080"
+ },
+
+ "data_db": {
+ "db_type": "redis",
+ "db_port": 6379,
+ "db_name": "10"
+ },
+
+ "stor_db": {
+ "db_password": "CGRateS.org"
+ },
+
+
+ "dispatchers":{
+ "enabled": true
+ },
+
+ "caches":{
+ //"remote_conns": ["*internal"],
+ },
+
+
+ "apiers": {
+ "enabled": true,
+ // "caches_conns":["broadcast_cache"]
+ },
+
+ // "rpc_conns": {
+ // "broadcast_cache": {
+ // "strategy": "*broadcast",
+ // "conns": [
+ // {"address": "127.0.0.1:2012", "transport":"*json"},
+ // {"address": "127.0.0.1:4012", "transport":"*json"},
+ // {"address": "127.0.0.1:6012", "transport":"*json"}
+ // ]
+ // }
+ // }
+
+}
\ No newline at end of file
diff --git a/data/conf/samples/dispatcher_opts_setter/cgrates.json b/data/conf/samples/dispatcher_opts_setter/cgrates.json
new file mode 100644
index 000000000..c8285a587
--- /dev/null
+++ b/data/conf/samples/dispatcher_opts_setter/cgrates.json
@@ -0,0 +1,51 @@
+{
+
+ "general": {
+ "node_id": "DispatcherOpts_Setter",
+ "log_level": 7
+ },
+
+
+ "listen": {
+ "rpc_json": ":6012",
+ "rpc_gob": ":6013",
+ "http": ":6080"
+ },
+
+ "data_db": {
+ "db_type": "redis",
+ "db_port": 6379,
+ "db_name": "10"
+ },
+
+ "stor_db": {
+ "db_password": "CGRateS.org"
+ },
+
+
+ "dispatchers":{
+ "enabled": false
+ },
+
+ "caches":{
+ //"remote_conns": ["*internal"],
+ },
+
+
+ "apiers": {
+ "enabled": true,
+ "caches_conns":["broadcast_cache"]
+ },
+
+ "rpc_conns": {
+ "broadcast_cache": {
+ "strategy": "*broadcast",
+ "conns": [
+ {"address": "127.0.0.1:2012", "transport":"*json"},
+ {"address": "127.0.0.1:4012", "transport":"*json"},
+ {"address": "127.0.0.1:6012", "transport":"*json"}
+ ]
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/dispatchers/caches.go b/dispatchers/caches.go
index 8a7c1677c..de5bd08de 100644
--- a/dispatchers/caches.go
+++ b/dispatchers/caches.go
@@ -84,6 +84,25 @@ func (dS *DispatcherService) CacheSv1HasItem(args *utils.ArgsGetCacheItemWithAPI
utils.MetaCaches, utils.CacheSv1HasItem, args, reply)
}
+func (dS *DispatcherService) CacheSv1GetItem(args *utils.ArgsGetCacheItemWithAPIOpts, reply *interface{}) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CacheSv1GetItem, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCaches, utils.CacheSv1GetItem, args, reply)
+}
+
// CacheSv1GetItemExpiryTime returns the expiryTime for an item
func (dS *DispatcherService) CacheSv1GetItemExpiryTime(args *utils.ArgsGetCacheItemWithAPIOpts,
reply *time.Time) (err error) {
@@ -198,6 +217,25 @@ func (dS *DispatcherService) CacheSv1PrecacheStatus(args *utils.AttrCacheIDsWith
}, utils.MetaCaches, utils.CacheSv1PrecacheStatus, args, reply)
}
+func (dS *DispatcherService) CacheSv1GetItemWithRemote(args *utils.ArgsGetCacheItemWithAPIOpts, reply *interface{}) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CacheSv1GetItemWithRemote, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCaches, utils.CacheSv1GetItemWithRemote, args, reply)
+}
+
// CacheSv1HasGroup checks existence of a group in cache
func (dS *DispatcherService) CacheSv1HasGroup(args *utils.ArgsGetGroupWithAPIOpts,
reply *bool) (err error) {
diff --git a/dispatchers/cores.go b/dispatchers/cores.go
new file mode 100644
index 000000000..ad604c074
--- /dev/null
+++ b/dispatchers/cores.go
@@ -0,0 +1,175 @@
+/*
+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
+*/
+
+package dispatchers
+
+import (
+ "time"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+func (dS *DispatcherService) CoreSv1Panic(args *utils.PanicMessageArgs, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1Panic, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1Panic, args, reply)
+}
+func (dS *DispatcherService) CoreSv1Ping(args *utils.CGREvent, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ if args != nil {
+ ev = args.Event
+ }
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1Ping, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1Ping, args, reply)
+}
+
+func (dS *DispatcherService) CoreSv1Sleep(args *utils.DurationArgs, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1Sleep, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1Sleep, args, reply)
+}
+
+func (dS *DispatcherService) CoreSv1StartCPUProfiling(args *utils.DirectoryArgs, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1StartCPUProfiling, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1StartCPUProfiling, args, reply)
+}
+func (dS *DispatcherService) CoreSv1StartMemoryProfiling(args *utils.MemoryPrf, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1StartMemoryProfiling, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1StartMemoryProfiling, args, reply)
+}
+func (dS *DispatcherService) CoreSv1Status(args *utils.TenantWithAPIOpts, reply *map[string]interface{}) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1Status, tnt,
+ utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1Status, args, reply)
+}
+func (dS *DispatcherService) CoreSv1StopCPUProfiling(args *utils.TenantWithAPIOpts, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1StopCPUProfiling,
+ tnt, utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1StopCPUProfiling, args, reply)
+}
+func (dS *DispatcherService) CoreSv1StopMemoryProfiling(args *utils.TenantWithAPIOpts, reply *string) (err error) {
+ tnt := dS.cfg.GeneralCfg().DefaultTenant
+ if args != nil && len(args.Tenant) != 0 {
+ tnt = args.Tenant
+ }
+ ev := make(map[string]interface{})
+ opts := make(map[string]interface{})
+ if args != nil {
+ opts = args.APIOpts
+ }
+ if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 {
+ if err = dS.authorize(utils.CoreSv1StopMemoryProfiling,
+ tnt, utils.IfaceAsString(opts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{Tenant: tnt, Event: ev, APIOpts: opts}, utils.MetaCore, utils.CoreSv1StopMemoryProfiling, args, reply)
+}
diff --git a/dispatchers/dispatchers.go b/dispatchers/dispatchers.go
index 708de8a04..46bd454ce 100644
--- a/dispatchers/dispatchers.go
+++ b/dispatchers/dispatchers.go
@@ -26,6 +26,7 @@ import (
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/guardian"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
)
@@ -81,7 +82,7 @@ func (dS *DispatcherService) authorize(method, tenant string, apiKey string, evT
Event: map[string]interface{}{
utils.APIKey: apiKey,
},
- APIOpts: map[string]interface{}{utils.Subsys: utils.MetaDispatchers},
+ APIOpts: map[string]interface{}{utils.MetaSubsys: utils.MetaDispatchers},
}
var rplyEv engine.AttrSProcessEventReply
if err = dS.authorizeEvent(ev, &rplyEv); err != nil {
@@ -187,6 +188,49 @@ func (dS *DispatcherService) Dispatch(ev *utils.CGREvent, subsys string,
if tnt == utils.EmptyString {
tnt = dS.cfg.GeneralCfg().DefaultTenant
}
+ var shouldDispatch bool
+ if shouldDispatch, err = utils.GetBoolOpts(ev, true, utils.OptsDispatchers); err != nil {
+ return utils.NewErrDispatcherS(err)
+ } else if !shouldDispatch {
+ return callDH(
+ newInternalHost(tnt), utils.EmptyString, nil,
+ serviceMethod, args, reply)
+ }
+ var dR *DispatcherRoute
+ var dPrfls engine.DispatcherProfiles
+ routeID := utils.IfaceAsString(ev.APIOpts[utils.OptsRouteID])
+ if routeID != utils.EmptyString { // overwrite routeID with RouteID:Subsystem for subsystem correct routing
+ routeID = utils.ConcatenatedKey(routeID, subsys)
+ guardID := utils.ConcatenatedKey(utils.DispatcherSv1, utils.OptsRouteID, routeID)
+ refID := guardian.Guardian.GuardIDs("", dS.cfg.GeneralCfg().LockingTimeout,
+ guardID) // lock the routeID so we can make sure we have time to execute only once before caching
+ defer guardian.Guardian.UnguardIDs(refID)
+ // use previously discovered route
+ argsCache := &utils.ArgsGetCacheItemWithAPIOpts{
+ Tenant: ev.Tenant,
+ APIOpts: map[string]interface{}{
+ utils.MetaSubsys: utils.MetaDispatchers,
+ utils.MetaNodeID: dS.cfg.GeneralCfg().NodeID,
+ },
+ ArgsGetCacheItem: utils.ArgsGetCacheItem{
+ CacheID: utils.CacheDispatcherRoutes,
+ ItemID: routeID,
+ }}
+ // item
+ var itmRemote interface{}
+ if err = dS.connMgr.Call(dS.cfg.CacheCfg().RemoteConns, nil,
+ utils.CacheSv1GetItem, argsCache, &itmRemote); err != nil &&
+ err.Error() != utils.ErrNotFound.Error() {
+ return utils.NewErrDispatcherS(err)
+ } else if err == nil { // not found
+ dR = itmRemote.(*DispatcherRoute)
+ routeID = utils.EmptyString // cancel cache replication
+ }
+ }
+ if dR != nil {
+ dPrfls = engine.DispatcherProfiles{
+ &engine.DispatcherProfile{Tenant: dR.Tenant, ID: dR.ProfileID}} // will be used bellow to retrieve the dispatcher
+ }
evNm := utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -194,10 +238,19 @@ func (dS *DispatcherService) Dispatch(ev *utils.CGREvent, subsys string,
utils.MetaMethod: serviceMethod,
},
}
- var dPrfls engine.DispatcherProfiles
- if dPrfls, err = dS.dispatcherProfilesForEvent(tnt, ev, evNm, subsys); err != nil {
- return utils.NewErrDispatcherS(err)
+ if dPrfls == nil { // did not discover it yet
+ if dPrfls, err = dS.dispatcherProfilesForEvent(tnt, ev, evNm, subsys); err != nil {
+ return utils.NewErrDispatcherS(err)
+ }
}
+ if len(dPrfls) == 0 {
+ return utils.NewErrDispatcherS(utils.ErrPrefixNotFound("PROFILE"))
+ }
+ if ev.APIOpts == nil {
+ ev.APIOpts = make(map[string]interface{})
+ }
+ ev.APIOpts[utils.MetaSubsys] = utils.MetaDispatchers // inject into args
+ ev.APIOpts[utils.MetaNodeID] = dS.cfg.GeneralCfg().NodeID
for _, dPrfl := range dPrfls {
tntID := dPrfl.TenantID()
// get or build the Dispatcher for the config
@@ -205,13 +258,37 @@ func (dS *DispatcherService) Dispatch(ev *utils.CGREvent, subsys string,
if x, ok := engine.Cache.Get(utils.CacheDispatchers,
tntID); ok && x != nil {
d = x.(Dispatcher)
- } else if d, err = newDispatcher(dPrfl); err != nil {
- return utils.NewErrDispatcherS(err)
+ } else { // dispatcher is not cached, build it here
+ if dPrfl.Hosts == nil { // dispatcher profile was not retrieved but built artificially above, try retrieving
+ if dPrfl, err = dS.dm.GetDispatcherProfile(dPrfl.Tenant, dPrfl.ID,
+ true, true, utils.NonTransactional); err != nil {
+ if err != utils.ErrNotFound {
+ return
+ }
+ // profile was not found
+ utils.Logger.Warning(fmt.Sprintf("<%s> could not find profile with tenant: <%s> and ID <%s> for routeID: <%s>",
+ utils.DispatcherS, dR.Tenant, dR.ProfileID, routeID))
+ if len(dPrfls) == 1 { // the only profile set does not exist anymore
+ return utils.NewErrDispatcherS(utils.ErrPrefixNotFound("PROFILE"))
+ }
+ continue
+ }
+ }
+ if d, err = newDispatcher(dPrfl); err != nil {
+ return utils.NewErrDispatcherS(err)
+ } else if err = engine.Cache.Set(utils.CacheDispatchers, tntID, d, // cache the built Dispatcher
+ nil, true, utils.EmptyString); err != nil {
+ return utils.NewErrDispatcherS(err)
+ }
}
- if err = engine.Cache.Set(utils.CacheDispatchers, tntID, d, nil, true, utils.EmptyString); err != nil {
- return utils.NewErrDispatcherS(err)
+ if routeID != utils.EmptyString && dR == nil { // first time we cache the route
+ dR = &DispatcherRoute{
+ Tenant: dPrfl.Tenant,
+ ProfileID: dPrfl.ID,
+ }
}
- if err = d.Dispatch(dS.dm, dS.fltrS, evNm, tnt, utils.IfaceAsString(ev.APIOpts[utils.OptsRouteID]), subsys, serviceMethod, args, reply); !rpcclient.IsNetworkError(err) {
+ if err = d.Dispatch(dS.dm, dS.fltrS, evNm, tnt, routeID, dR,
+ serviceMethod, args, reply); !rpcclient.IsNetworkError(err) {
return
}
}
@@ -230,7 +307,7 @@ func (dS *DispatcherService) V1GetProfilesForEvent(ev *utils.CGREvent,
utils.MetaVars: utils.MapStorage{
utils.MetaMethod: ev.APIOpts[utils.MetaMethod],
},
- }, utils.IfaceAsString(ev.APIOpts[utils.Subsys]))
+ }, utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys]))
if errDpfl != nil {
return utils.NewErrDispatcherS(errDpfl)
}
diff --git a/dispatchers/dispatchers_test.go b/dispatchers/dispatchers_test.go
index d7b2ec23e..2db47a9e5 100644
--- a/dispatchers/dispatchers_test.go
+++ b/dispatchers/dispatchers_test.go
@@ -79,11 +79,11 @@ func TestDispatcherServiceDispatcherProfileForEventGetDispatcherProfileNF(t *tes
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -104,7 +104,7 @@ func TestDispatcherServiceDispatcherProfileForEventMIIDENotFound(t *testing.T) {
dss := NewDispatcherService(dm, cfg, nil, connMng)
ev := &utils.CGREvent{}
tnt := ""
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err := dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -573,11 +573,11 @@ func TestDispatcherServiceDispatcherProfileForEventErrNil(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -620,11 +620,11 @@ func TestDispatcherV1GetProfileForEventReturn(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -673,11 +673,11 @@ func TestDispatcherServiceDispatcherProfileForEventErrNotFound(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAny,
+ utils.MetaSubsys: utils.MetaAny,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -720,11 +720,11 @@ func TestDispatcherServiceDispatcherProfileForEventErrNotFound2(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ""
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -772,11 +772,11 @@ func TestDispatcherServiceDispatcherProfileForEventErrNotFoundTime(t *testing.T)
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -820,11 +820,11 @@ func TestDispatcherServiceDispatcherProfileForEventErrNotFoundFilter(t *testing.
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -868,10 +868,10 @@ func TestDispatcherServiceDispatchDspErr(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
err = dss.Dispatch(ev, subsys, "", "", "")
expected := "DISPATCHER_ERROR:unsupported dispatch strategy: <>"
if err == nil || err.Error() != expected {
@@ -921,10 +921,10 @@ func TestDispatcherServiceDispatchDspErrHostNotFound(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
err = dss.Dispatch(ev, subsys, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
@@ -980,11 +980,11 @@ func TestDispatcherServiceDispatcherProfileForEventFoundFilter(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -1023,11 +1023,11 @@ func TestDispatcherServiceDispatcherProfileForEventNotNotFound(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err := dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -1085,11 +1085,11 @@ func TestDispatcherServiceDispatcherProfileForEventGetDispatcherError(t *testing
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
tnt := ev.Tenant
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
_, err = dss.dispatcherProfilesForEvent(tnt, ev, utils.MapStorage{
utils.MetaReq: ev.Event,
utils.MetaOpts: ev.APIOpts,
@@ -1141,10 +1141,10 @@ func TestDispatcherServiceDispatchDspErrHostNotFound2(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
err = dss.Dispatch(ev, subsys, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
@@ -1204,10 +1204,10 @@ func TestDispatcherServiceDispatchDspErrHostNotFound3(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaAccounts,
+ utils.MetaSubsys: utils.MetaAccounts,
},
}
- subsys := utils.IfaceAsString(ev.APIOpts[utils.Subsys])
+ subsys := utils.IfaceAsString(ev.APIOpts[utils.MetaSubsys])
err = dss.Dispatch(ev, subsys, "", "", "")
expected := "DISPATCHER_ERROR:NOT_IMPLEMENTED"
if err == nil || err.Error() != expected {
@@ -1238,7 +1238,7 @@ func TestDispatcherServiceCall2(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaDispatchers,
+ utils.MetaSubsys: utils.MetaDispatchers,
},
}
err := dsp.Call("DispatcherService.Test", args, &reply)
@@ -1270,7 +1270,7 @@ func TestDispatcherServiceCall3(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaDispatchers,
+ utils.MetaSubsys: utils.MetaDispatchers,
},
}
err := dsp.Call("DispatcherService.Test2", args, &reply)
@@ -1302,7 +1302,7 @@ func TestDispatcherServiceCall4(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaDispatchers,
+ utils.MetaSubsys: utils.MetaDispatchers,
},
}
err := dsp.Call("DispatcherService.Test3", args, &reply)
diff --git a/dispatchers/libdispatcher.go b/dispatchers/libdispatcher.go
index 5a65d0daa..c6b9d945d 100644
--- a/dispatchers/libdispatcher.go
+++ b/dispatchers/libdispatcher.go
@@ -24,6 +24,7 @@ import (
"math/rand"
"sort"
"sync"
+ "time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -33,7 +34,12 @@ import (
func init() {
gob.Register(new(LoadMetrics))
+ gob.Register(new(DispatcherRoute))
+}
+// DispatcherRoute is bounded to a routeID
+type DispatcherRoute struct {
+ Tenant, ProfileID, HostID string
}
// Dispatcher is responsible for routing requests to pool of connections
@@ -41,7 +47,7 @@ func init() {
type Dispatcher interface {
// Dispatch is used to send the method over the connections given
Dispatch(dm *engine.DataManager, flts *engine.FilterS,
- ev utils.DataProvider, tnt, routeID, subsystem string,
+ ev utils.DataProvider, tnt, routeID string, dR *DispatcherRoute,
serviceMethod string, args interface{}, reply interface{}) (err error)
}
@@ -69,6 +75,7 @@ func newDispatcher(pfl *engine.DispatcherProfile) (d Dispatcher, err error) {
return
}
+// getDispatcherHosts returns a list of host IDs matching the event with filters
func getDispatcherHosts(fltrs *engine.FilterS, ev utils.DataProvider, tnt string, hosts engine.DispatcherHostProfiles) (hostIDs engine.DispatcherHostIDs, err error) {
hostIDs = make(engine.DispatcherHostIDs, 0, len(hosts))
for _, host := range hosts {
@@ -86,16 +93,19 @@ func getDispatcherHosts(fltrs *engine.FilterS, ev utils.DataProvider, tnt string
return
}
+// hostSorter is the sorting interface used by singleDispatcher
type hostSorter interface {
Sort(fltrs *engine.FilterS, ev utils.DataProvider, tnt string, hosts engine.DispatcherHostProfiles) (hostIDs engine.DispatcherHostIDs, err error)
}
+// noSort will just return the matching hosts for the event
type noSort struct{}
func (noSort) Sort(fltrs *engine.FilterS, ev utils.DataProvider, tnt string, hosts engine.DispatcherHostProfiles) (hostIDs engine.DispatcherHostIDs, err error) {
return getDispatcherHosts(fltrs, ev, tnt, hosts)
}
+// randomSort will randomize the matching hosts for the event
type randomSort struct{}
func (randomSort) Sort(fltrs *engine.FilterS, ev utils.DataProvider, tnt string, hosts engine.DispatcherHostProfiles) (hostIDs engine.DispatcherHostIDs, err error) {
@@ -105,6 +115,8 @@ func (randomSort) Sort(fltrs *engine.FilterS, ev utils.DataProvider, tnt string,
return getDispatcherHosts(fltrs, ev, tnt, hosts)
}
+// roundRobinSort will sort the matching hosts for the event in a round-robin fashion via nextIDx
+// which will be increased on each Sort iteration
type roundRobinSort struct{ nextIDx int }
func (rs *roundRobinSort) Sort(fltrs *engine.FilterS, ev utils.DataProvider, tnt string, hosts engine.DispatcherHostProfiles) (hostIDs engine.DispatcherHostIDs, err error) {
@@ -124,6 +136,7 @@ func (rs *roundRobinSort) Sort(fltrs *engine.FilterS, ev utils.DataProvider, tnt
return getDispatcherHosts(fltrs, ev, tnt, dh)
}
+// newSingleDispatcher is the constructor for singleDispatcher struct
func newSingleDispatcher(hosts engine.DispatcherHostProfiles, params map[string]interface{}, tntID string, sorter hostSorter) (_ Dispatcher, err error) {
if dflt, has := params[utils.MetaDefaultRatio]; has {
var ratio int64
@@ -153,69 +166,64 @@ func newSingleDispatcher(hosts engine.DispatcherHostProfiles, params map[string]
}, nil
}
+// singleResultDispatcher routes the event to a single host
+// implements Dispatcher interface
type singleResultDispatcher struct {
sorter hostSorter
hosts engine.DispatcherHostProfiles
}
func (sd *singleResultDispatcher) Dispatch(dm *engine.DataManager, flts *engine.FilterS,
- ev utils.DataProvider, tnt, routeID, subsystem string,
+ ev utils.DataProvider, tnt, routeID string, dR *DispatcherRoute,
serviceMethod string, args interface{}, reply interface{}) (err error) {
- var dH *engine.DispatcherHost
- if routeID != utils.EmptyString {
- // overwrite routeID with RouteID:Subsystem
- routeID = utils.ConcatenatedKey(routeID, subsystem)
- // use previously discovered route
- if x, ok := engine.Cache.Get(utils.CacheDispatcherRoutes,
- routeID); ok && x != nil {
- dH = x.(*engine.DispatcherHost)
- if err = dH.Call(serviceMethod, args, reply); !rpcclient.IsNetworkError(err) {
- return
- }
+ if routeID != utils.EmptyString && dR.HostID != utils.EmptyString { // route to previously discovered route
+ if err = callDHwithID(tnt, dR.HostID, routeID, dR, dm,
+ serviceMethod, args, reply); err == nil ||
+ (err != utils.ErrNotFound && !rpcclient.IsNetworkError(err)) { // successful dispatch with normal errors
+ return
}
+ // not found or network errors will continue
+ utils.Logger.Warning(fmt.Sprintf("<%s> error <%s> dispatching to host with identity <%q>",
+ utils.DispatcherS, err.Error(), dR.HostID))
}
var hostIDs []string
if hostIDs, err = sd.sorter.Sort(flts, ev, tnt, sd.hosts); err != nil {
return
+ } else if len(hostIDs) == 0 { // in case we do not match any host
+ return utils.ErrHostNotFound
}
- var called bool
for _, hostID := range hostIDs {
- if dH, err = dm.GetDispatcherHost(tnt, hostID, true, true, utils.NonTransactional); err != nil {
- if err == utils.ErrNotFound {
- utils.Logger.Warning(fmt.Sprintf("<%s> could not find host with ID %q",
- utils.DispatcherS, hostID))
- err = nil
- continue
+ var dRh *DispatcherRoute
+ if routeID != utils.EmptyString {
+ dRh = &DispatcherRoute{
+ Tenant: dR.Tenant,
+ ProfileID: dR.ProfileID,
+ HostID: hostID,
}
- err = utils.NewErrDispatcherS(err)
+ }
+ if err = callDHwithID(tnt, hostID, routeID, dRh, dm,
+ serviceMethod, args, reply); err == nil ||
+ (err != utils.ErrNotFound && !rpcclient.IsNetworkError(err)) { // successful dispatch with normal errors
return
}
- called = true
- if err = dH.Call(serviceMethod, args, reply); rpcclient.IsNetworkError(err) {
- continue
+ if err != nil {
+ // not found or network errors will continue with standard dispatching
+ utils.Logger.Warning(fmt.Sprintf("<%s> error <%s> dispatching to host with identity <%q>",
+ utils.DispatcherS, err.Error(), hostID))
}
- if routeID != utils.EmptyString { // cache the discovered route
- if err = engine.Cache.Set(utils.CacheDispatcherRoutes, routeID, dH,
- nil, true, utils.EmptyString); err != nil {
- return
- }
- }
- break
- }
- if !called { // in case we do not match any host
- err = utils.ErrHostNotFound
- return
}
return
}
+// broadcastDispatcher routes the event to multiple hosts in a pool
+// implements the Dispatcher interface
type broadcastDispatcher struct {
strategy string
hosts engine.DispatcherHostProfiles
}
func (b *broadcastDispatcher) Dispatch(dm *engine.DataManager, flts *engine.FilterS,
- ev utils.DataProvider, tnt, routeID, subsystem string,
+ ev utils.DataProvider, tnt, routeID string, dR *DispatcherRoute,
serviceMethod string, args interface{}, reply interface{}) (err error) {
var hostIDs []string
if hostIDs, err = getDispatcherHosts(flts, ev, tnt, b.hosts); err != nil {
@@ -235,7 +243,19 @@ func (b *broadcastDispatcher) Dispatch(dm *engine.DataManager, flts *engine.Filt
return utils.NewErrDispatcherS(err)
}
hasHosts = true
- pool.AddClient(dH)
+ var dRh *DispatcherRoute
+ if routeID != utils.EmptyString {
+ dRh = &DispatcherRoute{
+ Tenant: dR.Tenant,
+ ProfileID: dR.ProfileID,
+ HostID: hostID,
+ }
+ }
+ pool.AddClient(&lazyDH{
+ dh: dH,
+ routeID: routeID,
+ dR: dRh,
+ })
}
if !hasHosts { // in case we do not match any host
return utils.ErrHostNotFound
@@ -251,9 +271,8 @@ type loadDispatcher struct {
}
func (ld *loadDispatcher) Dispatch(dm *engine.DataManager, flts *engine.FilterS,
- ev utils.DataProvider, tnt, routeID, subsystem string,
+ ev utils.DataProvider, tnt, routeID string, dR *DispatcherRoute,
serviceMethod string, args interface{}, reply interface{}) (err error) {
- var dH *engine.DispatcherHost
var lM *LoadMetrics
if x, ok := engine.Cache.Get(utils.CacheDispatcherLoads, ld.tntID); ok && x != nil {
var canCast bool
@@ -263,56 +282,47 @@ func (ld *loadDispatcher) Dispatch(dm *engine.DataManager, flts *engine.FilterS,
} else if lM, err = newLoadMetrics(ld.hosts, ld.defaultRatio); err != nil {
return
}
-
- if routeID != utils.EmptyString {
- // overwrite routeID with RouteID:Subsystem
- routeID = utils.ConcatenatedKey(routeID, subsystem)
- // use previously discovered route
- if x, ok := engine.Cache.Get(utils.CacheDispatcherRoutes,
- routeID); ok && x != nil {
- dH = x.(*engine.DispatcherHost)
- lM.incrementLoad(dH.ID, ld.tntID)
- err = dH.Call(serviceMethod, args, reply)
- lM.decrementLoad(dH.ID, ld.tntID) // call ended
- if !rpcclient.IsNetworkError(err) {
- return
- }
+ if routeID != utils.EmptyString && dR.HostID != utils.EmptyString { // route to previously discovered route
+ lM.incrementLoad(dR.HostID, ld.tntID)
+ err = callDHwithID(tnt, dR.HostID, routeID, dR, dm,
+ serviceMethod, args, reply)
+ lM.decrementLoad(dR.HostID, ld.tntID) // call ended
+ if err == nil ||
+ (err != utils.ErrNotFound && !rpcclient.IsNetworkError(err)) { // successful dispatch with normal errors
+ return
}
+ // not found or network errors will continue with standard dispatching
+ utils.Logger.Warning(fmt.Sprintf("<%s> error <%s> dispatching to host with id <%q>",
+ utils.DispatcherS, err.Error(), dR.HostID))
}
var hostIDs []string
if hostIDs, err = ld.sorter.Sort(flts, ev, tnt, lM.getHosts(ld.hosts)); err != nil {
return
+ } else if len(hostIDs) == 0 { // in case we do not match any host
+ return utils.ErrHostNotFound
}
- var called bool
for _, hostID := range hostIDs {
- if dH, err = dm.GetDispatcherHost(tnt, hostID, true, true, utils.NonTransactional); err != nil {
- if err == utils.ErrNotFound {
- utils.Logger.Warning(fmt.Sprintf("<%s> could not find host with ID %q",
- utils.DispatcherS, hostID))
- err = nil
- continue
+ var dRh *DispatcherRoute
+ if routeID != utils.EmptyString {
+ dRh = &DispatcherRoute{
+ Tenant: dR.Tenant,
+ ProfileID: dR.ProfileID,
+ HostID: hostID,
}
- err = utils.NewErrDispatcherS(err)
+ }
+ lM.incrementLoad(hostID, ld.tntID)
+ err = callDHwithID(tnt, hostID, routeID, dRh, dm,
+ serviceMethod, args, reply)
+ lM.decrementLoad(hostID, ld.tntID) // call ended
+ if err == nil ||
+ (err != utils.ErrNotFound && !rpcclient.IsNetworkError(err)) { // successful dispatch with normal errors
return
}
- called = true
- lM.incrementLoad(hostID, ld.tntID)
- err = dH.Call(serviceMethod, args, reply)
- lM.decrementLoad(hostID, ld.tntID) // call ended
- if rpcclient.IsNetworkError(err) {
- continue
+ if err != nil {
+ // not found or network errors will continue with standard dispatching
+ utils.Logger.Warning(fmt.Sprintf("<%s> error <%s> dispatching to host with id <%q>",
+ utils.DispatcherS, err.Error(), hostID))
}
- if routeID != utils.EmptyString { // cache the discovered route
- if err = engine.Cache.Set(utils.CacheDispatcherRoutes, routeID, dH,
- nil, true, utils.EmptyString); err != nil {
- return
- }
- }
- break
- }
- if !called { // in case we do not match any host
- err = utils.ErrHostNotFound
- return
}
return
}
@@ -390,3 +400,65 @@ func (lM *LoadMetrics) decrementLoad(hostID, tntID string) {
engine.Cache.ReplicateSet(utils.CacheDispatcherLoads, tntID, lM)
lM.mutex.Unlock()
}
+
+// lazyDH is created for the broadcast strategy so we can make sure host exists during setup phase
+type lazyDH struct {
+ dh *engine.DispatcherHost
+ routeID string
+ dR *DispatcherRoute
+}
+
+func (l *lazyDH) Call(method string, args, reply interface{}) (err error) {
+ return callDH(l.dh, l.routeID, l.dR, method, args, reply)
+}
+
+func callDH(dh *engine.DispatcherHost, routeID string, dR *DispatcherRoute,
+ method string, args, reply interface{}) (err error) {
+ if routeID != utils.EmptyString { // cache the discovered route before dispatching
+ argsCache := &utils.ArgCacheReplicateSet{
+ Tenant: dh.Tenant,
+ APIOpts: map[string]interface{}{
+ utils.MetaSubsys: utils.MetaDispatchers,
+ utils.MetaNodeID: config.CgrConfig().GeneralCfg().NodeID,
+ },
+ CacheID: utils.CacheDispatcherRoutes,
+ ItemID: routeID,
+ Value: dR,
+ }
+ if err = engine.Cache.SetWithReplicate(argsCache); err != nil {
+ return
+ }
+ }
+ if err = dh.Call(method, args, reply); err != nil {
+ return
+ }
+ return
+}
+
+// callDHwithID is a wrapper on callDH using ID of the host, will also cache once the call is successful
+func callDHwithID(tnt, hostID, routeID string, dR *DispatcherRoute, dm *engine.DataManager,
+ serviceMethod string, args, reply interface{}) (err error) {
+ var dH *engine.DispatcherHost
+ if dH, err = dm.GetDispatcherHost(tnt, hostID, true, true, utils.NonTransactional); err != nil {
+ return
+ }
+ if err = callDH(dH, routeID, dR, serviceMethod, args, reply); err != nil {
+ return
+ }
+ return
+}
+
+// newInternalHost returns an internal host as needed for internal dispatching
+func newInternalHost(tnt string) *engine.DispatcherHost {
+ return &engine.DispatcherHost{
+ Tenant: tnt,
+ RemoteHost: &config.RemoteHost{
+ ID: utils.MetaInternal,
+ Address: utils.MetaInternal,
+ ConnectAttempts: 1,
+ Reconnects: 1,
+ ConnectTimeout: time.Second,
+ ReplyTimeout: time.Second,
+ },
+ }
+}
diff --git a/dispatchers/libdispatcher_test.go b/dispatchers/libdispatcher_test.go
index bd9774c47..492dace78 100644
--- a/dispatchers/libdispatcher_test.go
+++ b/dispatchers/libdispatcher_test.go
@@ -388,7 +388,7 @@ func TestLibDispatcherSingleResultDispatcherDispatch(t *testing.T) {
wgDsp := &singleResultDispatcher{sorter: new(noSort)}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -399,7 +399,7 @@ func TestLibDispatcherSingleResultDispatcherDispatchRouteID(t *testing.T) {
wgDsp := &singleResultDispatcher{sorter: new(roundRobinSort)}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "routeID", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "routeID", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -410,7 +410,7 @@ func TestLibDispatcherBroadcastDispatcherDispatch(t *testing.T) {
wgDsp := &broadcastDispatcher{hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -421,7 +421,7 @@ func TestLibDispatcherBroadcastDispatcherDispatchRouteID(t *testing.T) {
wgDsp := &broadcastDispatcher{hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "routeID", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "routeID", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -432,7 +432,7 @@ func TestLibDispatcherLoadDispatcherDispatch(t *testing.T) {
wgDsp := &loadDispatcher{sorter: new(randomSort)}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -449,7 +449,7 @@ func TestLibDispatcherLoadDispatcherDispatchHostsID(t *testing.T) {
}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "routeID", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "routeID", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -474,7 +474,7 @@ func TestLibDispatcherLoadStrategyDispatchCaseHosts(t *testing.T) {
}
dataDB := engine.NewInternalDB(nil, nil, true, config.CgrConfig().DataDbCfg().Items)
dM := engine.NewDataManager(dataDB, config.CgrConfig().CacheCfg(), nil)
- err := wgDsp.Dispatch(dM, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(dM, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -497,7 +497,7 @@ func TestLibDispatcherLoadStrategyDispatchCaseHostsError(t *testing.T) {
defaultRatio: 1,
sorter: new(noSort),
}
- err := wgDsp.Dispatch(nil, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "DISPATCHER_ERROR:NO_DATABASE_CONNECTION"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -527,7 +527,7 @@ func TestLibDispatcherLoadStrategyDispatchCaseHostsCastError(t *testing.T) {
defaultRatio: 1,
sorter: new(noSort),
}
- err := wgDsp.Dispatch(nil, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "cannot cast false to *LoadMetrics"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -552,7 +552,7 @@ func TestLibDispatcherLoadStrategyDispatchCaseHostsCastError2(t *testing.T) {
defaultRatio: 1,
sorter: new(noSort),
}
- err := wgDsp.Dispatch(nil, nil, nil, "", "", "", "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "", "", &DispatcherRoute{}, "", "", "")
expected := "cannot convert field: false to int"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -577,7 +577,7 @@ func TestLibDispatcherSingleResultDispatcherCastError(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherRoutes, "testID:*attributes",
value, nil, true, utils.NonTransactional)
wgDsp := &singleResultDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "", "testID", utils.MetaAttributes, "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "", "testID", &DispatcherRoute{}, "", "", "")
expected := "DISPATCHER_ERROR:NO_DATABASE_CONNECTION"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -615,7 +615,7 @@ func TestLibDispatcherSingleResultDispatcherCastError2(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherRoutes, "testID:*attributes",
value, nil, true, utils.NonTransactional)
wgDsp := &singleResultDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
expected := "UNSUPPORTED_SERVICE_METHOD"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -642,7 +642,7 @@ func TestLibDispatcherBroadcastDispatcherDispatchError1(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherRoutes, "testID:*attributes",
value, nil, true, utils.NonTransactional)
wgDsp := &broadcastDispatcher{hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, "", "", "")
expected := "DISPATCHER_ERROR:NO_DATABASE_CONNECTION"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -660,7 +660,7 @@ func TestLibDispatcherBroadcastDispatcherDispatchError2(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherHosts, "testTenant:testID",
nil, nil, true, utils.NonTransactional)
wgDsp := &broadcastDispatcher{hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -686,7 +686,7 @@ func TestLibDispatcherBroadcastDispatcherDispatchError3(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherHosts, "testTenant:testID",
value, nil, true, utils.NonTransactional)
wgDsp := &broadcastDispatcher{hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, "", "", "")
if err != nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
}
@@ -711,7 +711,7 @@ func TestLibDispatcherLoadDispatcherCacheError(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherRoutes, "testID:*attributes",
value, nil, true, utils.NonTransactional)
wgDsp := &loadDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, "", "", "")
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, "", "", "")
expected := "HOST_NOT_FOUND"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -743,7 +743,7 @@ func TestLibDispatcherLoadDispatcherCacheError2(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherRoutes, "testID:*attributes",
value, nil, true, utils.NonTransactional)
wgDsp := &loadDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
expected := "UNSUPPORTED_SERVICE_METHOD"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -800,7 +800,7 @@ func TestLibDispatcherLoadDispatcherCacheError3(t *testing.T) {
defaultRatio: 0,
sorter: new(noSort),
}
- err := wgDsp.Dispatch(dm, nil, nil, "testTENANT", "testID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(dm, nil, nil, "testTENANT", "testID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
if err != nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
}
@@ -868,7 +868,7 @@ func TestLibDispatcherLoadDispatcherCacheError4(t *testing.T) {
defaultRatio: 0,
sorter: new(noSort),
}
- err := wgDsp.Dispatch(dm, nil, nil, "testTENANT", "testID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(dm, nil, nil, "testTENANT", "testID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
expected := "DISCONNECTED"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -921,7 +921,7 @@ func TestLibDispatcherLoadDispatcherCacheError5(t *testing.T) {
defaultRatio: 0,
sorter: new(noSort),
}
- err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(nil, nil, nil, "testTenant", "testID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
if err == nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "connection is shut down", err)
}
@@ -951,7 +951,7 @@ func TestLibDispatcherSingleResultDispatcherCase1(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherHosts, "testTenant:testID",
value, nil, true, utils.NonTransactional)
wgDsp := &singleResultDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(dm, nil, nil, "testTenant", "", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(dm, nil, nil, "testTenant", "", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
if err == nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", "connection is shut down", err)
}
@@ -988,7 +988,7 @@ func TestLibDispatcherSingleResultDispatcherCase2(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherHosts, "testTenant:testID",
value, nil, true, utils.NonTransactional)
wgDsp := &singleResultDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(dm, nil, nil, "testTenant", "routeID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(dm, nil, nil, "testTenant", "routeID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
if err != nil {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", nil, err)
}
@@ -1035,7 +1035,7 @@ func TestLibDispatcherSingleResultDispatcherCase3(t *testing.T) {
engine.Cache.SetWithoutReplicate(utils.CacheDispatcherHosts, "testTenant:testID",
value, nil, true, utils.NonTransactional)
wgDsp := &singleResultDispatcher{sorter: new(noSort), hosts: engine.DispatcherHostProfiles{{ID: "testID"}}}
- err := wgDsp.Dispatch(dm, nil, nil, "testTenant", "routeID", utils.MetaAttributes, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
+ err := wgDsp.Dispatch(dm, nil, nil, "testTenant", "routeID", &DispatcherRoute{}, utils.AttributeSv1Ping, &utils.CGREvent{}, &wgDsp)
expected := "DISCONNECTED"
if err == nil || err.Error() != expected {
t.Errorf("\nExpected <%+v>, \nReceived <%+v>", expected, err)
@@ -1055,7 +1055,7 @@ func TestLibDispatcherDispatchFilterError(t *testing.T) {
}},
}
expErrMsg := "inline parse error for string: <*wrongType>"
- if err := dsp.Dispatch(nil, flts, nil, "", "", "", "", "", ""); err == nil || err.Error() != expErrMsg {
+ if err := dsp.Dispatch(nil, flts, nil, "", "", &DispatcherRoute{}, "", "", ""); err == nil || err.Error() != expErrMsg {
t.Errorf("Expected error: %s received: %v", expErrMsg, err)
}
dsp = &loadDispatcher{
@@ -1066,7 +1066,7 @@ func TestLibDispatcherDispatchFilterError(t *testing.T) {
}},
defaultRatio: 1,
}
- if err := dsp.Dispatch(nil, flts, nil, "", "", "", "", "", ""); err == nil || err.Error() != expErrMsg {
+ if err := dsp.Dispatch(nil, flts, nil, "", "", &DispatcherRoute{}, "", "", ""); err == nil || err.Error() != expErrMsg {
t.Errorf("Expected error: %s received: %v", expErrMsg, err)
}
dsp = &broadcastDispatcher{
@@ -1075,7 +1075,7 @@ func TestLibDispatcherDispatchFilterError(t *testing.T) {
FilterIDs: []string{"*wrongType"},
}},
}
- if err := dsp.Dispatch(nil, flts, nil, "", "", "", "", "", ""); err == nil || err.Error() != expErrMsg {
+ if err := dsp.Dispatch(nil, flts, nil, "", "", &DispatcherRoute{}, "", "", ""); err == nil || err.Error() != expErrMsg {
t.Errorf("Expected error: %s received: %v", expErrMsg, err)
}
}
@@ -1090,7 +1090,7 @@ func TestLibDispatcherDispatchHostNotFound(t *testing.T) {
ID: "testID",
}},
}
- if err := dsp.Dispatch(db, flts, nil, "", "", "", "", "", ""); err != utils.ErrHostNotFound {
+ if err := dsp.Dispatch(db, flts, nil, "", "", &DispatcherRoute{}, "", "", ""); err != utils.ErrHostNotFound {
t.Errorf("Expected error: %s received: %v", utils.ErrHostNotFound, err)
}
}
diff --git a/dispatchers/sessions_it_test.go b/dispatchers/sessions_it_test.go
index eb283c649..61bdbfa30 100644
--- a/dispatchers/sessions_it_test.go
+++ b/dispatchers/sessions_it_test.go
@@ -61,7 +61,7 @@ var sTestsDspSession = []func(t *testing.T){
testDspSessionForceDisconect,
}
-//Test start here
+// Test start here
func TestDspSessionS(t *testing.T) {
var config1, config2, config3 string
switch *dbType {
@@ -405,7 +405,7 @@ func testDspSessionUpdate(t *testing.T) {
APIOpts: map[string]interface{}{
utils.OptsAPIKey: "ses12345",
"*attrProfileIDs": nil,
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
},
},
}
@@ -480,7 +480,7 @@ func testDspSessionUpdate2(t *testing.T) {
APIOpts: map[string]interface{}{
utils.OptsAPIKey: "ses12345",
"*attrProfileIDs": nil,
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
},
},
}
@@ -637,7 +637,7 @@ func testDspSessionProcessEvent(t *testing.T) {
"*attrProfileIDs": nil,
"*rsUnits": 1.,
"*rsUsageID": "TestSSv1It2",
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
},
},
}
@@ -718,7 +718,7 @@ func testDspSessionProcessEvent2(t *testing.T) {
"*attrProfileIDs": nil,
"*rsUnits": 1.,
"*rsUsageID": "TestSSv1It2",
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
},
},
}
diff --git a/ees/ees.go b/ees/ees.go
index 89846999d..e501d0d0c 100644
--- a/ees/ees.go
+++ b/ees/ees.go
@@ -106,7 +106,7 @@ func (eeS *EventExporterS) attrSProcessEvent(cgrEv *utils.CGREvent, attrIDs []st
if cgrEv.APIOpts == nil {
cgrEv.APIOpts = make(map[string]interface{})
}
- cgrEv.APIOpts[utils.Subsys] = utils.MetaEEs
+ cgrEv.APIOpts[utils.MetaSubsys] = utils.MetaEEs
cgrEv.APIOpts[utils.OptsAttributesProfileIDs] = attrIDs
cgrEv.APIOpts[utils.OptsContext] = utils.FirstNonEmpty(ctx,
utils.IfaceAsString(cgrEv.APIOpts[utils.OptsContext]), utils.MetaEEs)
diff --git a/ees/rpc_test.go b/ees/rpc_test.go
index bc0eb1f59..939c63568 100644
--- a/ees/rpc_test.go
+++ b/ees/rpc_test.go
@@ -175,7 +175,7 @@ func TestRPCPrepareMap(t *testing.T) {
utils.Usage: 21,
},
APIOpts: map[string]interface{}{
- utils.Subsys: "*attributes",
+ utils.MetaSubsys: "*attributes",
},
}
diff --git a/engine/caches.go b/engine/caches.go
index 3a75efc6f..0177d7424 100644
--- a/engine/caches.go
+++ b/engine/caches.go
@@ -36,19 +36,21 @@ var Cache *CacheS
func init() {
Cache = NewCacheS(config.CgrConfig(), nil, nil)
+ // Register objects for cache replication/remotes
+ //AttributeS
gob.Register(new(AttributeProfile))
gob.Register(new(AttributeProfileWithAPIOpts))
- // Threshold
+ // ThresholdS
gob.Register(new(Threshold))
gob.Register(new(ThresholdProfile))
gob.Register(new(ThresholdProfileWithAPIOpts))
gob.Register(new(ThresholdWithAPIOpts))
- // Resource
+ // ResourceS
gob.Register(new(Resource))
gob.Register(new(ResourceProfile))
gob.Register(new(ResourceProfileWithAPIOpts))
gob.Register(new(ResourceWithAPIOpts))
- // Stats
+ // StatS
gob.Register(new(StatQueue))
gob.Register(new(StatQueueProfile))
gob.Register(new(StatQueueProfileWithAPIOpts))
@@ -57,10 +59,10 @@ func init() {
// RouteS
gob.Register(new(RouteProfile))
gob.Register(new(RouteProfileWithAPIOpts))
- // Filters
+ // FilterS
gob.Register(new(Filter))
gob.Register(new(FilterWithAPIOpts))
- // Dispatcher
+ // DispatcherS
gob.Register(new(DispatcherHost))
gob.Register(new(DispatcherHostProfile))
gob.Register(new(DispatcherHostWithAPIOpts))
@@ -80,6 +82,7 @@ func init() {
gob.Register(new(StatAverage))
gob.Register(new(StatDistinct))
+ // others
gob.Register([]interface{}{})
gob.Register([]map[string]interface{}{})
gob.Register(map[string]interface{}{})
@@ -151,6 +154,21 @@ func (chS *CacheS) Set(chID, itmID string, value interface{},
return chS.ReplicateSet(chID, itmID, value)
}
+// ReplicateSet replicates an item to ReplicationConns
+func (chS *CacheS) ReplicateSet(chID, itmID string, value interface{}) (err error) {
+ if len(chS.cfg.CacheCfg().ReplicationConns) == 0 ||
+ !chS.cfg.CacheCfg().Partitions[chID].Replicate {
+ return
+ }
+ var reply string
+ return connMgr.Call(chS.cfg.CacheCfg().ReplicationConns, nil, utils.CacheSv1ReplicateSet,
+ &utils.ArgCacheReplicateSet{
+ CacheID: chID,
+ ItemID: itmID,
+ Value: value,
+ }, &reply)
+}
+
// SetWithoutReplicate is an exported method from TransCache
// handled Replicate functionality
func (chS *CacheS) SetWithoutReplicate(chID, itmID string, value interface{},
@@ -158,6 +176,18 @@ func (chS *CacheS) SetWithoutReplicate(chID, itmID string, value interface{},
chS.tCache.Set(chID, itmID, value, groupIDs, commit, transID)
}
+// SetWithReplicate combines local set with replicate, receiving the arguments needed by dispatcher
+func (chS *CacheS) SetWithReplicate(args *utils.ArgCacheReplicateSet) (err error) {
+ chS.tCache.Set(args.CacheID, args.ItemID, args.Value, args.GroupIDs, true, utils.EmptyString)
+ if len(chS.cfg.CacheCfg().ReplicationConns) == 0 ||
+ !chS.cfg.CacheCfg().Partitions[args.CacheID].Replicate {
+ return
+ }
+ var reply string
+ return connMgr.Call(chS.cfg.CacheCfg().ReplicationConns, nil,
+ utils.CacheSv1ReplicateSet, args, &reply)
+}
+
// HasItem is an exported method from TransCache
func (chS *CacheS) HasItem(chID, itmID string) (has bool) {
return chS.tCache.HasItem(chID, itmID)
@@ -168,6 +198,26 @@ func (chS *CacheS) Get(chID, itmID string) (interface{}, bool) {
return chS.tCache.Get(chID, itmID)
}
+// GetWithRemote queries locally the cache, followed by remotes
+func (chS *CacheS) GetWithRemote(args *utils.ArgsGetCacheItemWithAPIOpts) (itm interface{}, err error) {
+ var has bool
+ if itm, has = chS.tCache.Get(args.CacheID, args.ItemID); has {
+ return
+ }
+ if len(chS.cfg.CacheCfg().RemoteConns) == 0 ||
+ !chS.cfg.CacheCfg().Partitions[args.CacheID].Remote {
+ return
+ }
+ // item was not found locally, query from remote
+ var itmRemote interface{}
+ if err = connMgr.Call(chS.cfg.CacheCfg().RemoteConns, nil,
+ utils.CacheSv1GetItem, args, &itmRemote); err != nil &&
+ err.Error() == utils.ErrNotFound.Error() {
+ return nil, utils.ErrNotFound // correct the error coming as string type
+ }
+ return
+}
+
// GetItemIDs is an exported method from TransCache
func (chS *CacheS) GetItemIDs(chID, prfx string) (itmIDs []string) {
return chS.tCache.GetItemIDs(chID, prfx)
@@ -276,6 +326,28 @@ func (chS *CacheS) V1HasItem(args *utils.ArgsGetCacheItemWithAPIOpts,
return
}
+// V1GetItem returns a single item from the cache
+func (chS *CacheS) V1GetItem(args *utils.ArgsGetCacheItemWithAPIOpts,
+ reply *interface{}) (err error) {
+ itmIface, has := chS.tCache.Get(args.CacheID, args.ItemID)
+ if !has {
+ return utils.ErrNotFound
+ }
+ *reply = itmIface
+ return
+}
+
+// V1GetItemWithRemote queries the item from remote if not found locally
+func (chS *CacheS) V1GetItemWithRemote(args *utils.ArgsGetCacheItemWithAPIOpts,
+ reply *interface{}) (err error) {
+ var itmIface interface{}
+ if itmIface, err = chS.GetWithRemote(args); err != nil {
+ return
+ }
+ *reply = itmIface
+ return
+}
+
func (chS *CacheS) V1GetItemExpiryTime(args *utils.ArgsGetCacheItemWithAPIOpts,
reply *time.Time) (err error) {
expTime, has := chS.tCache.GetItemExpiryTime(args.CacheID, args.ItemID)
@@ -394,7 +466,7 @@ func (chS *CacheS) cacheDataFromDB(attrs *utils.AttrReloadCacheWithAPIOpts, repl
return
}
-//populateCacheLoadIDs populate cacheLoadIDs based on attrs
+// populateCacheLoadIDs populate cacheLoadIDs based on attrs
func populateCacheLoadIDs(loadIDs map[string]int64, attrs map[string][]string) (cacheLoadIDs map[string]int64) {
cacheLoadIDs = make(map[string]int64)
//based on IDs of each type populate cacheLoadIDs and add into cache
@@ -406,22 +478,7 @@ func populateCacheLoadIDs(loadIDs map[string]int64, attrs map[string][]string) (
return
}
-// ReplicateSet replicate an item to ReplicationConns
-func (chS *CacheS) ReplicateSet(chID, itmID string, value interface{}) (err error) {
- if len(chS.cfg.CacheCfg().ReplicationConns) == 0 ||
- !chS.cfg.CacheCfg().Partitions[chID].Replicate {
- return
- }
- var reply string
- return connMgr.Call(chS.cfg.CacheCfg().ReplicationConns, nil, utils.CacheSv1ReplicateSet,
- &utils.ArgCacheReplicateSet{
- CacheID: chID,
- ItemID: itmID,
- Value: value,
- }, &reply)
-}
-
-// V1ReplicateSet replicate an item
+// V1ReplicateSet receives an item via replication to store in the cache
func (chS *CacheS) V1ReplicateSet(args *utils.ArgCacheReplicateSet, reply *string) (err error) {
if cmp, canCast := args.Value.(utils.Compiler); canCast {
if err = cmp.Compile(); err != nil {
diff --git a/engine/cdrs.go b/engine/cdrs.go
index de15477d1..8665426d2 100644
--- a/engine/cdrs.go
+++ b/engine/cdrs.go
@@ -373,7 +373,7 @@ func (cdrS *CDRServer) attrSProcessEvent(cgrEv *utils.CGREvent) (err error) {
if cgrEv.APIOpts == nil {
cgrEv.APIOpts = make(map[string]interface{})
}
- cgrEv.APIOpts[utils.Subsys] = utils.MetaCDRs
+ cgrEv.APIOpts[utils.MetaSubsys] = utils.MetaCDRs
ctx, has := cgrEv.APIOpts[utils.OptsContext]
cgrEv.APIOpts[utils.OptsContext] = utils.FirstNonEmpty(
utils.IfaceAsString(ctx),
diff --git a/engine/chargers.go b/engine/chargers.go
index 8911852f6..20bc1a1c7 100644
--- a/engine/chargers.go
+++ b/engine/chargers.go
@@ -114,7 +114,7 @@ func (cS *ChargerService) processEvent(tnt string, cgrEv *utils.CGREvent) (rply
clonedEv := cgrEv.Clone()
clonedEv.Tenant = tnt
clonedEv.Event[utils.RunID] = cP.RunID
- clonedEv.APIOpts[utils.Subsys] = utils.MetaChargers
+ clonedEv.APIOpts[utils.MetaSubsys] = utils.MetaChargers
rply[i] = &ChrgSProcessEventReply{
ChargerSProfile: cP.ID,
CGREvent: clonedEv,
diff --git a/engine/chargers_test.go b/engine/chargers_test.go
index 5d39a0c73..5c5c39522 100644
--- a/engine/chargers_test.go
+++ b/engine/chargers_test.go
@@ -192,7 +192,7 @@ func TestChargerMatchingChargerProfilesForEvent(t *testing.T) {
utils.Weight: "200.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
},
{
@@ -359,7 +359,7 @@ func TestChargerProcessEvent(t *testing.T) {
utils.Weight: "200.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
},
{
@@ -521,7 +521,7 @@ func TestChargersmatchingChargerProfilesForEventChargerProfileNotFound(t *testin
utils.Weight: "10.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
}
@@ -567,7 +567,7 @@ func TestChargersmatchingChargerProfilesForEventDoesNotPass(t *testing.T) {
utils.Weight: "10.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
}
@@ -617,7 +617,7 @@ func TestChargersmatchingChargerProfilesForEventErrGetChPrf(t *testing.T) {
utils.Weight: "10.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
}
diff --git a/engine/routes.go b/engine/routes.go
index cd1c66e52..fe97a39d3 100644
--- a/engine/routes.go
+++ b/engine/routes.go
@@ -574,7 +574,7 @@ func (rpS *RouteService) V1GetRoutes(args *utils.CGREvent, reply *SortedRoutesLi
if args.APIOpts == nil {
args.APIOpts = make(map[string]interface{})
}
- args.APIOpts[utils.Subsys] = utils.MetaRoutes
+ args.APIOpts[utils.MetaSubsys] = utils.MetaRoutes
context := utils.GetStringOpts(args, rpS.cgrcfg.RouteSCfg().Opts.Context, utils.OptsContext)
args.APIOpts[utils.OptsContext] = utils.FirstNonEmpty(context, utils.MetaRoutes)
var rplyEv AttrSProcessEventReply
diff --git a/engine/tpreader_test.go b/engine/tpreader_test.go
index 7d320d414..10e6d0aeb 100644
--- a/engine/tpreader_test.go
+++ b/engine/tpreader_test.go
@@ -47,7 +47,7 @@ func TestTPReaderCallCacheNoCaching(t *testing.T) {
utils.CacheResources: {},
}
opts := map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
}
err := CallCache(cM, []string{}, utils.MetaNone, args, []string{}, opts, true, "cgrates.org")
@@ -73,7 +73,7 @@ func TestTPReaderCallCacheReloadCacheFirstCallErr(t *testing.T) {
utils.CacheSv1ReloadCache: func(args, reply interface{}) error {
expArgs := &utils.AttrReloadCacheWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
FilterIDs: []string{"cgrates.org:FLTR_ID1", "cgrates.org:FLTR_ID2"},
Tenant: "cgrates.org",
@@ -100,7 +100,7 @@ func TestTPReaderCallCacheReloadCacheFirstCallErr(t *testing.T) {
}
cacheIDs := []string{}
opts := map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
}
var buf bytes.Buffer
@@ -141,7 +141,7 @@ func TestTPReaderCallCacheReloadCacheSecondCallErr(t *testing.T) {
utils.CacheSv1Clear: func(args, reply interface{}) error {
expArgs := &utils.AttrCacheIDsWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
CacheIDs: []string{"cacheID"},
Tenant: "cgrates.org",
@@ -168,7 +168,7 @@ func TestTPReaderCallCacheReloadCacheSecondCallErr(t *testing.T) {
}
cacheIDs := []string{"cacheID"}
opts := map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
}
var buf bytes.Buffer
@@ -218,7 +218,7 @@ func TestTPReaderCallCacheLoadCache(t *testing.T) {
utils.CacheSv1LoadCache: func(args, reply interface{}) error {
expArgs := &utils.AttrReloadCacheWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
FilterIDs: []string{"cgrates.org:FLTR_ID1", "cgrates.org:FLTR_ID2"},
Tenant: "cgrates.org",
@@ -235,7 +235,7 @@ func TestTPReaderCallCacheLoadCache(t *testing.T) {
utils.CacheSv1Clear: func(args, reply interface{}) error {
expArgs := &utils.AttrCacheIDsWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
CacheIDs: []string{"cacheID"},
Tenant: "cgrates.org",
@@ -262,7 +262,7 @@ func TestTPReaderCallCacheLoadCache(t *testing.T) {
}
cacheIDs := []string{"cacheID"}
opts := map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
}
err := CallCache(cM, cacheConns, caching, args, cacheIDs, opts, false, "cgrates.org")
@@ -287,7 +287,7 @@ func TestTPReaderCallCacheRemoveItems(t *testing.T) {
utils.CacheSv1RemoveItems: func(args, reply interface{}) error {
expArgs := &utils.AttrReloadCacheWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
FilterIDs: []string{"cgrates.org:FLTR_ID1", "cgrates.org:FLTR_ID2"},
Tenant: "cgrates.org",
@@ -304,7 +304,7 @@ func TestTPReaderCallCacheRemoveItems(t *testing.T) {
utils.CacheSv1Clear: func(args, reply interface{}) error {
expArgs := &utils.AttrCacheIDsWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
CacheIDs: []string{"cacheID"},
Tenant: "cgrates.org",
@@ -331,7 +331,7 @@ func TestTPReaderCallCacheRemoveItems(t *testing.T) {
}
cacheIDs := []string{"cacheID"}
opts := map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
}
err := CallCache(cM, cacheConns, caching, args, cacheIDs, opts, false, "cgrates.org")
@@ -356,7 +356,7 @@ func TestTPReaderCallCacheClear(t *testing.T) {
utils.CacheSv1Clear: func(args, reply interface{}) error {
expArgs := &utils.AttrCacheIDsWithAPIOpts{
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
Tenant: "cgrates.org",
}
@@ -382,7 +382,7 @@ func TestTPReaderCallCacheClear(t *testing.T) {
}
cacheIDs := []string{}
opts := map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
}
err := CallCache(cM, cacheConns, caching, args, cacheIDs, opts, false, "cgrates.org")
diff --git a/engine/z_chargers_test.go b/engine/z_chargers_test.go
index ac34eac35..4baa17496 100644
--- a/engine/z_chargers_test.go
+++ b/engine/z_chargers_test.go
@@ -70,7 +70,7 @@ func TestChargersmatchingChargerProfilesForEventErrPass(t *testing.T) {
utils.Weight: "10.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
Time: &cgrEvTm,
}
@@ -131,7 +131,7 @@ func TestChargersmatchingChargerProfilesForEventNotActive(t *testing.T) {
utils.Weight: "10.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
},
Time: &cgrEvTm,
}
@@ -192,7 +192,7 @@ func TestChargersprocessEventNoConnIDs(t *testing.T) {
utils.Weight: "10.0",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProcessRuns: 2,
},
Time: &cgrEvTm,
@@ -373,7 +373,7 @@ func TestChargersprocessEventCallErr(t *testing.T) {
"RunID": utils.MetaDefault,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: []string(nil),
},
},
diff --git a/general_tests/dispatcher_opts_it_test.go b/general_tests/dispatcher_opts_it_test.go
new file mode 100644
index 000000000..3bd280549
--- /dev/null
+++ b/general_tests/dispatcher_opts_it_test.go
@@ -0,0 +1,646 @@
+//go:build integration
+// +build integration
+
+/*
+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
+*/
+
+package general_tests
+
+import (
+ "net/rpc"
+ "path"
+ "testing"
+ "time"
+
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+)
+
+var (
+ setterCfgPath string
+ setterCfg *config.CGRConfig
+ setterRPC *rpc.Client
+
+ dspOptsCfgPath string
+ apierCfgPath string
+ dspOptsCfg *config.CGRConfig
+ apierCfg *config.CGRConfig
+ dspOptsRPC *rpc.Client
+ apierRPC *rpc.Client
+ dspOptsConfigDIR string
+ dpsOptsTest = []func(t *testing.T){
+ testDispatcherOptsSetterInitCfg,
+ testDispatcherOptsSetterInitDataDb,
+ testDispatcherOptsSetterStartEngine,
+ testDispatcherOptsSetterRPCConn,
+ // Start engine without Dispatcher on engine 4012
+ testDispatcherOptsAPIerInitCfg,
+ testDispatcherOptsAPIerInitDataDb,
+ testDispatcherOptsAPIerStartEngine,
+ testDispatcherOptsAPIerRPCConn,
+ testDispatcherOptsSetterSetDispatcherProfile,
+ // testDispatcherOptsAPIerSetDispatcherProfile,
+
+ // Start engine without Dispatcher on engine 2012 with profiles in database (*dispatchers:false)
+ testDispatcherOptsDSPInitCfg,
+ testDispatcherOptsDSPStartEngine,
+ testDispatcherOptsDSPRPCConn,
+ testDispatcherOptsCoreStatus, // self localhost(:2012) CoresV1Status
+
+ testDispatcherOptsSetterSetDispatcherHost4012,
+ // testDispatcherOptsAPIerSetDispatcherHost4012,
+ testDispatcherOptsCoreStatusHost4012,
+
+ testDispatcherOptsSetterSetDispatcherProfileDoubleHost,
+ // testDispatcherOptsAPIerSetDispatcherProfileDoubleHost,
+ testDispatcherOptsCoreStatusWithRouteID,
+
+ testDispatcherOptsSetterSetDispatcherHostInexistent,
+ // testDispatcherOptsAPIerSetDispatcherHostInexistent,
+ testDispatcherOptsCoreStatusWithRouteID2,
+
+ testDispatcherOptsCoreStatusWithoutRouteID,
+
+ testDispatcherOptsDSPStopEngine,
+ testDispatcherOptsAPIerStopEngine,
+ // testDispatcherOptsSetterStopEngine,
+ }
+)
+
+func TestDispatcherOpts(t *testing.T) {
+ for _, test := range dpsOptsTest {
+ t.Run(dspOptsConfigDIR, test)
+ }
+}
+
+func testDispatcherOptsAPIerInitCfg(t *testing.T) {
+ dspOptsConfigDIR = "dispatcher_opts_apier"
+ var err error
+ apierCfgPath = path.Join(*dataDir, "conf", "samples", dspOptsConfigDIR)
+ apierCfg, err = config.NewCGRConfigFromPath(apierCfgPath)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func testDispatcherOptsAPIerInitDataDb(t *testing.T) {
+ if err := engine.InitDataDb(apierCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Start CGR Engine woth Dispatcher enabled
+func testDispatcherOptsAPIerStartEngine(t *testing.T) {
+ if _, err := engine.StartEngine(apierCfgPath, *waitRater); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testDispatcherOptsAPIerRPCConn(t *testing.T) {
+ var err error
+ apierRPC, err = newRPCClient(apierCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testDispatcherOptsAPIerSetDispatcherProfile(t *testing.T) {
+ // Set DispatcherHost
+ var replyStr string
+ setDispatcherHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ Tenant: "cgrates.org",
+ RemoteHost: &config.RemoteHost{
+ ID: "SELF_ENGINE",
+ Address: "127.0.0.1:4012",
+ Transport: "*json",
+ ConnectAttempts: 1,
+ Reconnects: 3,
+ ConnectTimeout: time.Minute,
+ ReplyTimeout: 2 * time.Minute,
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherHost, setDispatcherHost, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherHost: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+
+ // Set DispatcherProfile
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 10,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "SELF_ENGINE",
+ Weight: 5,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+
+func testDispatcherOptsDSPInitCfg(t *testing.T) {
+ dspOptsConfigDIR = "dispatcher_opts" //changed with the cfg with dispatcher on
+ var err error
+ dspOptsCfgPath = path.Join(*dataDir, "conf", "samples", dspOptsConfigDIR)
+ dspOptsCfg, err = config.NewCGRConfigFromPath(dspOptsCfgPath)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+// Start CGR Engine woth Dispatcher enabled
+func testDispatcherOptsDSPStartEngine(t *testing.T) {
+ if _, err := engine.StartEngine(dspOptsCfgPath, *waitRater); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testDispatcherOptsDSPRPCConn(t *testing.T) {
+ var err error
+ dspOptsRPC, err = newRPCClient(dspOptsCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testDispatcherOptsCoreStatus(t *testing.T) {
+ //SELF_ENGINE HOST
+ var reply map[string]interface{}
+ ev := utils.TenantWithAPIOpts{
+ Tenant: "cgrates.org",
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := dspOptsRPC.Call(utils.CoreSv1Status, &ev, &reply); err != nil {
+ t.Error(err)
+ } else {
+ /*
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ */
+ }
+}
+
+func testDispatcherOptsAPIerSetDispatcherHost4012(t *testing.T) {
+ // Set DispatcherHost on 4012 host
+ var replyStr string
+ setDispatcherHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ Tenant: "cgrates.org",
+ RemoteHost: &config.RemoteHost{
+ ID: "HOST4012",
+ Address: "127.0.0.1:4012",
+ Transport: "*json",
+ ConnectAttempts: 1,
+ Reconnects: 3,
+ ConnectTimeout: time.Minute,
+ ReplyTimeout: 2 * time.Minute,
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherHost, setDispatcherHost, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherHost: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+
+ // Set DispatcherProfile
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 10,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "HOST4012",
+ Weight: 10,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+
+func testDispatcherOptsCoreStatusHost4012(t *testing.T) {
+ // status just for HOST4012
+ var reply map[string]interface{}
+ ev := utils.TenantWithAPIOpts{
+ Tenant: "cgrates.org",
+ }
+ if err := dspOptsRPC.Call(utils.CoreSv1Status, &ev, &reply); err != nil {
+ t.Error(err)
+ } else {
+ /*
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ */
+ }
+}
+
+func testDispatcherOptsAPIerSetDispatcherProfileDoubleHost(t *testing.T) {
+ // Set DispatcherProfile with both engines
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 10,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "SELF_ENGINE",
+ Weight: 5,
+ },
+ {
+ ID: "HOST4012",
+ Weight: 10,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ var replyStr string
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+
+func testDispatcherOptsCoreStatusWithRouteID(t *testing.T) {
+ // now it will dispatch in both engines
+ var reply map[string]interface{}
+ ev := utils.TenantWithAPIOpts{
+ Tenant: "cgrates.org",
+ APIOpts: map[string]interface{}{
+ utils.OptsRouteID: "account#dan.bogos",
+ },
+ }
+ if err := dspOptsRPC.Call(utils.CoreSv1Status, &ev, &reply); err != nil {
+ t.Error(err)
+ } else {
+ /*
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ */
+ }
+}
+
+func testDispatcherOptsAPIerSetDispatcherHostInexistent(t *testing.T) {
+ // Set DispatcherHost on 4012 host
+ var replyStr string
+ setDispatcherHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ Tenant: "cgrates.org",
+ RemoteHost: &config.RemoteHost{
+ ID: "INEXISTENT",
+ Address: "127.0.0.1:1223",
+ Transport: "*json",
+ ConnectAttempts: 1,
+ Reconnects: 3,
+ ConnectTimeout: time.Minute,
+ ReplyTimeout: 2 * time.Minute,
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherHost, setDispatcherHost, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherHost: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+
+ // Set DispatcherProfile Different with an inexistent engine opened, but with a bigger weight(this should match now)
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 20,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "INEXISTENT",
+ Weight: 10,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := apierRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+
+func testDispatcherOptsCoreStatusWithRouteID2(t *testing.T) {
+ // because we have the routeID it will match DSP1 and last host matched, host4012
+ // so again, both engines will match
+ var reply map[string]interface{}
+ ev := utils.TenantWithAPIOpts{
+ Tenant: "cgrates.org",
+ APIOpts: map[string]interface{}{
+ utils.OptsRouteID: "account#dan.bogos",
+ },
+ }
+ if err := dspOptsRPC.Call(utils.CoreSv1Status, &ev, &reply); err != nil {
+ t.Error(err)
+ } else {
+ /*
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ */
+ }
+}
+
+func testDispatcherOptsCoreStatusWithoutRouteID(t *testing.T) {
+ // because we have the routeID it will match DSP1 and last host matched, host4012
+ // so again, both engines will match
+ var reply map[string]interface{}
+ ev := utils.TenantWithAPIOpts{
+ Tenant: "cgrates.org",
+ }
+ if err := dspOptsRPC.Call(utils.CoreSv1Status, &ev, &reply); err != nil {
+ t.Error(err)
+ } else {
+ /*
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ */
+ }
+}
+
+func testDispatcherOptsDSPStopEngine(t *testing.T) {
+ if err := engine.KillEngine(*waitRater); err != nil {
+ t.Error(err)
+ }
+}
+
+func testDispatcherOptsAPIerStopEngine(t *testing.T) {
+ if err := engine.KillEngine(*waitRater); err != nil {
+ t.Error(err)
+ }
+}
+
+// ----------------------------
+
+func testDispatcherOptsSetterInitCfg(t *testing.T) {
+ dspOptsConfigDIR = "dispatcher_opts_setter"
+ var err error
+ setterCfgPath = path.Join(*dataDir, "conf", "samples", dspOptsConfigDIR)
+ setterCfg, err = config.NewCGRConfigFromPath(setterCfgPath)
+ if err != nil {
+ t.Error(err)
+ }
+}
+func testDispatcherOptsSetterInitDataDb(t *testing.T) {
+ if err := engine.InitDataDb(setterCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+func testDispatcherOptsSetterStartEngine(t *testing.T) {
+ if _, err := engine.StartEngine(setterCfgPath, *waitRater); err != nil {
+ t.Fatal(err)
+ }
+}
+func testDispatcherOptsSetterRPCConn(t *testing.T) {
+ var err error
+ setterRPC, err = newRPCClient(setterCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+func testDispatcherOptsSetterSetDispatcherProfile(t *testing.T) {
+ // Set DispatcherHost
+ var replyStr string
+ setDispatcherHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ Tenant: "cgrates.org",
+ RemoteHost: &config.RemoteHost{
+ ID: "SELF_ENGINE",
+ Address: "127.0.0.1:4012",
+ Transport: "*json",
+ ConnectAttempts: 1,
+ Reconnects: 3,
+ ConnectTimeout: time.Minute,
+ ReplyTimeout: 2 * time.Minute,
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherHost, setDispatcherHost, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherHost: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+
+ // Set DispatcherProfile
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 10,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "SELF_ENGINE",
+ Weight: 5,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+func testDispatcherOptsSetterSetDispatcherHost4012(t *testing.T) {
+ // Set DispatcherHost on 4012 host
+ var replyStr string
+ setDispatcherHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ Tenant: "cgrates.org",
+ RemoteHost: &config.RemoteHost{
+ ID: "HOST4012",
+ Address: "127.0.0.1:4012",
+ Transport: "*json",
+ ConnectAttempts: 1,
+ Reconnects: 3,
+ ConnectTimeout: time.Minute,
+ ReplyTimeout: 2 * time.Minute,
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherHost, setDispatcherHost, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherHost: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+
+ // Set DispatcherProfile
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 10,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "HOST4012",
+ Weight: 10,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+func testDispatcherOptsSetterSetDispatcherProfileDoubleHost(t *testing.T) {
+ // Set DispatcherProfile with both engines
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 10,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "SELF_ENGINE",
+ Weight: 5,
+ },
+ {
+ ID: "HOST4012",
+ Weight: 10,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ var replyStr string
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+func testDispatcherOptsSetterSetDispatcherHostInexistent(t *testing.T) {
+ // Set DispatcherHost on 4012 host
+ var replyStr string
+ setDispatcherHost := &engine.DispatcherHostWithAPIOpts{
+ DispatcherHost: &engine.DispatcherHost{
+ Tenant: "cgrates.org",
+ RemoteHost: &config.RemoteHost{
+ ID: "INEXISTENT",
+ Address: "127.0.0.1:1223",
+ Transport: "*json",
+ ConnectAttempts: 1,
+ Reconnects: 3,
+ ConnectTimeout: time.Minute,
+ ReplyTimeout: 2 * time.Minute,
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherHost, setDispatcherHost, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherHost: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+
+ // Set DispatcherProfile Different with an inexistent engine opened, but with a bigger weight(this should match now)
+ setDispatcherProfile := &engine.DispatcherProfileWithAPIOpts{
+ DispatcherProfile: &engine.DispatcherProfile{
+ Tenant: "cgrates.org",
+ ID: "DSP1",
+ Strategy: "*weight",
+ Subsystems: []string{utils.MetaAny},
+ Weight: 20,
+ Hosts: engine.DispatcherHostProfiles{
+ {
+ ID: "INEXISTENT",
+ Weight: 10,
+ },
+ },
+ },
+ APIOpts: map[string]interface{}{
+ utils.OptsDispatchers: false,
+ },
+ }
+ if err := setterRPC.Call(utils.APIerSv1SetDispatcherProfile, setDispatcherProfile, &replyStr); err != nil {
+ t.Error("Unexpected error when calling APIerSv1.SetDispatcherProfile: ", err)
+ } else if replyStr != utils.OK {
+ t.Error("Unexpected reply returned", replyStr)
+ }
+}
+
+func testDispatcherOptsSetterStopEngine(t *testing.T) {
+
+}
diff --git a/general_tests/filters_it_test.go b/general_tests/filters_it_test.go
index 55d53608c..f96cd2a03 100644
--- a/general_tests/filters_it_test.go
+++ b/general_tests/filters_it_test.go
@@ -938,7 +938,7 @@ func testV1FltrChargerSuffix(t *testing.T) {
utils.Destination: "999",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: []interface{}{"*constant:*req.Subject:intraState"},
},
},
@@ -976,7 +976,7 @@ func testV1FltrChargerSuffix(t *testing.T) {
utils.Destination: "999",
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaChargers,
+ utils.MetaSubsys: utils.MetaChargers,
utils.OptsAttributesProfileIDs: []interface{}{"*constant:*req.Subject:interState"},
},
},
diff --git a/general_tests/session3_it_test.go b/general_tests/session3_it_test.go
index 07dac0a47..15e9226a2 100644
--- a/general_tests/session3_it_test.go
+++ b/general_tests/session3_it_test.go
@@ -185,7 +185,7 @@ func testSes3ItProcessEvent(t *testing.T) {
utils.Usage: 300000000000.0,
},
APIOpts: map[string]interface{}{
- utils.Subsys: utils.MetaSessionS,
+ utils.MetaSubsys: utils.MetaSessionS,
utils.OptsAPIKey: "ses12345",
utils.MetaEventType: utils.StatUpdate,
"*attrProfileIDs": nil,
diff --git a/services/dispatchers.go b/services/dispatchers.go
index b94782917..49ee29bd4 100644
--- a/services/dispatchers.go
+++ b/services/dispatchers.go
@@ -115,6 +115,9 @@ func (dspS *DispatcherService) Start() (err error) {
dspS.server.RpcRegisterName(utils.ChargerSv1,
v1.NewDispatcherChargerSv1(dspS.dspS))
+ dspS.server.RpcRegisterName(utils.CoreSv1,
+ v1.NewDispatcherCoreSv1(dspS.dspS))
+
dspS.server.RpcRegisterName(utils.Responder,
v1.NewDispatcherResponder(dspS.dspS))
diff --git a/servmanager/servmanager.go b/servmanager/servmanager.go
index e224aacaa..4f1565003 100644
--- a/servmanager/servmanager.go
+++ b/servmanager/servmanager.go
@@ -47,7 +47,7 @@ func NewServiceManager(cfg *config.CGRConfig, shdChan *utils.SyncedChan, shdWg *
type ServiceManager struct {
sync.RWMutex // lock access to any shared data
cfg *config.CGRConfig
- subsystems map[string]Service
+ subsystems map[string]Service // active subsystems managed by SM
shdChan *utils.SyncedChan
shdWg *sync.WaitGroup
diff --git a/sessions/sessions.go b/sessions/sessions.go
index b6f7af46f..0256ab5dd 100644
--- a/sessions/sessions.go
+++ b/sessions/sessions.go
@@ -3886,7 +3886,7 @@ func (sS *SessionS) processAttributes(cgrEv *utils.CGREvent, attrIDs []string,
if cgrEv.APIOpts == nil {
cgrEv.APIOpts = make(engine.MapEvent)
}
- cgrEv.APIOpts[utils.Subsys] = utils.MetaSessionS
+ cgrEv.APIOpts[utils.MetaSubsys] = utils.MetaSessionS
cgrEv.APIOpts[utils.OptsAttributesProfileIDs] = attrIDs
ctx, has := cgrEv.APIOpts[utils.OptsContext]
cgrEv.APIOpts[utils.OptsContext] = utils.FirstNonEmpty(
diff --git a/utils/apitpdata.go b/utils/apitpdata.go
index 926ee40f3..53fd21cc0 100644
--- a/utils/apitpdata.go
+++ b/utils/apitpdata.go
@@ -957,7 +957,7 @@ type AttrDisconnectSession struct {
Reason string
}
-//MetricWithFilters is used in TPStatProfile
+// MetricWithFilters is used in TPStatProfile
type MetricWithFilters struct {
FilterIDs []string
MetricID string
@@ -1499,11 +1499,12 @@ type DPRArgs struct {
}
type ArgCacheReplicateSet struct {
- CacheID string
- ItemID string
- Value interface{}
- APIOpts map[string]interface{}
- Tenant string
+ CacheID string
+ ItemID string
+ Value interface{}
+ Tenant string
+ APIOpts map[string]interface{}
+ GroupIDs []string
}
// Compiler are objects that need post compiling
diff --git a/utils/consts.go b/utils/consts.go
index 9585a2436..aa625e978 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -943,6 +943,7 @@ const (
MetaRoutes = "*routes"
MetaAttributes = "*attributes"
MetaLoadIDs = "*load_ids"
+ MetaNodeID = "*node_id"
)
// MetaMetrics
@@ -1127,7 +1128,7 @@ const (
ArgDispatcherField = "ArgDispatcher"
)
-//Filter types
+// Filter types
const (
MetaNot = "*not"
MetaString = "*string"
@@ -1501,6 +1502,7 @@ const (
CoreSv1 = "CoreSv1"
CoreSv1Status = "CoreSv1.Status"
CoreSv1Ping = "CoreSv1.Ping"
+ CoreSv1Panic = "CoreSv1.Panic"
CoreSv1Sleep = "CoreSv1.Sleep"
CoreSv1StartCPUProfiling = "CoreSv1.StartCPUProfiling"
CoreSv1StopCPUProfiling = "CoreSv1.StopCPUProfiling"
@@ -1682,6 +1684,8 @@ const (
CacheSv1GetCacheStats = "CacheSv1.GetCacheStats"
CacheSv1GetItemIDs = "CacheSv1.GetItemIDs"
CacheSv1HasItem = "CacheSv1.HasItem"
+ CacheSv1GetItem = "CacheSv1.GetItem"
+ CacheSv1GetItemWithRemote = "CacheSv1.GetItemWithRemote"
CacheSv1GetItemExpiryTime = "CacheSv1.GetItemExpiryTime"
CacheSv1RemoveItem = "CacheSv1.RemoveItem"
CacheSv1RemoveItems = "CacheSv1.RemoveItems"
@@ -1737,7 +1741,7 @@ const (
EeSv1ProcessEvent = "EeSv1.ProcessEvent"
)
-//cgr_ variables
+// cgr_ variables
const (
CGRAccount = "cgr_account"
CGRRoute = "cgr_route"
@@ -1754,7 +1758,7 @@ const (
CGROpts = "cgr_opts"
)
-//CSV file name
+// CSV file name
const (
TimingsCsv = "Timings.csv"
DestinationsCsv = "Destinations.csv"
@@ -2476,6 +2480,7 @@ const (
OptsAPIKey = "*apiKey"
OptsRouteID = "*routeID"
OptsDispatchersProfilesCount = "*dispatchersProfilesCount"
+ OptsDispatchers = "*dispatcherS"
// EEs
OptsEEsVerbose = "*eesVerbose"
// Resources
@@ -2504,7 +2509,7 @@ const (
OptsRefund = "*refund"
// Others
OptsContext = "*context"
- Subsys = "*subsys"
+ MetaSubsys = "*subsys"
MetaMethod = "*reqMethod"
OptsAttributesProfileIDs = "*attrProfileIDs"
OptsAttributesProcessRuns = "*attrProcessRuns"
@@ -2691,7 +2696,7 @@ const (
Opts = "Opts"
)
-//CMD constants
+// CMD constants
const (
//Common
VerboseCgr = "verbose"
diff --git a/utils/coreutils.go b/utils/coreutils.go
index 9201b0d49..47e7e13f8 100644
--- a/utils/coreutils.go
+++ b/utils/coreutils.go
@@ -167,6 +167,7 @@ func UUIDSha1Prefix() string {
// Round return rounded version of x with prec precision.
//
// Special cases are:
+//
// Round(±0) = ±0
// Round(±Inf) = ±Inf
// Round(NaN) = NaN
@@ -202,7 +203,7 @@ func Round(x float64, prec int, method string) float64 {
return rounder / pow
}
-//RoundStatDuration is used in engine package for stat metrics that has duration (e.g acd metric, tcd metric, etc...)
+// RoundStatDuration is used in engine package for stat metrics that has duration (e.g acd metric, tcd metric, etc...)
func RoundStatDuration(x time.Duration, prec int) time.Duration {
return x.Round(time.Duration(math.Pow10(9 - prec)))
}
@@ -429,7 +430,7 @@ func InfieldSplit(val string) []string {
return strings.Split(val, InfieldSep)
}
-//Splited Unzip in small functions to have better coverage
+// Splited Unzip in small functions to have better coverage
func Unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
@@ -577,10 +578,11 @@ func Clone(a, b interface{}) error {
// Used as generic function logic for various fields
// Attributes
-// source - the base source
-// width - the field width
-// strip - if present it will specify the strip strategy, when missing strip will not be allowed
-// padding - if present it will specify the padding strategy to use, left, right, zeroleft, zeroright
+//
+// source - the base source
+// width - the field width
+// strip - if present it will specify the strip strategy, when missing strip will not be allowed
+// padding - if present it will specify the padding strategy to use, left, right, zeroleft, zeroright
func FmtFieldWidth(fieldID, source string, width int, strip, padding string, mandatory bool) (string, error) {
if mandatory && len(source) == 0 {
return "", fmt.Errorf("Empty source value for fieldID: <%s>", fieldID)
@@ -1076,19 +1078,19 @@ func VerifyHash(hash string, dataKeys ...string) bool {
return err == nil
}
-//newBoolGen initialize an efficient boolean generator
+// newBoolGen initialize an efficient boolean generator
func newBoolGen() *boolGen {
return &boolGen{src: math_rand.NewSource(time.Now().UnixNano())}
}
-//boolGen is an efficient boolean generator
+// boolGen is an efficient boolean generator
type boolGen struct {
src math_rand.Source
cache int64
remaining int
}
-//RandomBool generate a random boolean
+// RandomBool generate a random boolean
func (b *boolGen) RandomBool() bool {
if b.remaining == 0 {
b.cache, b.remaining = b.src.Int63(), 63
@@ -1148,3 +1150,9 @@ func SplitPath(rule string, sep byte, n int) (splt []string) {
splt = append(splt, rule[st:])
return
}
+
+type PanicMessageArgs struct {
+ Tenant string
+ APIOpts map[string]interface{}
+ Message string
+}