diff --git a/agents/fsagent.go b/agents/fsagent.go index 8c4234a9d..44f9390fb 100644 --- a/agents/fsagent.go +++ b/agents/fsagent.go @@ -211,7 +211,8 @@ func (fsa *FSsessions) onChannelPark(fsev FSEvent, connIdx int) { } } if authReply.RouteProfiles != nil { - fsArray := SliceAsFsArray(authReply.RouteProfiles.RoutesWithParams()) + fsArray := SliceAsFsArray(authReply.RouteProfiles.RoutesWithParams( + config.CgrConfig().FsAgentCfg().RouteProfile)) if _, err := fsa.conns[connIdx].SendApiCmd(fmt.Sprintf("uuid_setvar %s %s %s\n\n", fsev.GetUUID(), utils.CGRRoutes, fsArray)); err != nil { utils.Logger.Info(fmt.Sprintf("<%s> error setting routes: %s", diff --git a/agents/fsevent_test.go b/agents/fsevent_test.go index 13b1e06d7..e76f7d793 100644 --- a/agents/fsevent_test.go +++ b/agents/fsevent_test.go @@ -677,7 +677,7 @@ func TestSliceAsArraySortingParameter(t *testing.T) { }, }} expFs := "ARRAY::4|:rt1|:rt2|:RT1|:RT2" - if fsArray := SliceAsFsArray(eSplrs.RoutesWithParams()); expFs != fsArray { + if fsArray := SliceAsFsArray(eSplrs.RoutesWithParams(false)); expFs != fsArray { t.Errorf("Expected %+v, received %+v", expFs, fsArray) } } diff --git a/agents/kamevent.go b/agents/kamevent.go index edc37b86c..c67f90293 100644 --- a/agents/kamevent.go +++ b/agents/kamevent.go @@ -253,7 +253,8 @@ func (kev KamEvent) AsKamAuthReply(authArgs *sessions.V1AuthorizeArgs, } } if authArgs.GetRoutes && authReply.RouteProfiles != nil { - kar.Routes = authReply.RouteProfiles.Digest() + kar.Routes = authReply.RouteProfiles.Digest( + config.CgrConfig().KamAgentCfg().Enabled) } if authArgs.ProcessThresholds && authReply.ThresholdIDs != nil { @@ -340,7 +341,8 @@ func (kev KamEvent) AsKamProcessMessageReply(procEvArgs *sessions.V1ProcessMessa kar.MaxUsage = int(utils.Round(procEvReply.MaxUsage.Seconds(), 0, utils.MetaRoundingMiddle)) } if procEvArgs.GetRoutes && procEvReply.RouteProfiles != nil { - kar.Routes = procEvReply.RouteProfiles.Digest() + kar.Routes = procEvReply.RouteProfiles.Digest( + config.CgrConfig().KamAgentCfg().RouteProfile) } if procEvArgs.ProcessThresholds { diff --git a/config/config_defaults.go b/config/config_defaults.go index 909a04d42..3acf6ae83 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -706,6 +706,7 @@ const CGRATES_CFG_JSON = ` "enabled": false, // starts the Asterisk agent: "sessions_conns": ["*birpc_internal"], "create_cdr": false, // create CDR out of events and sends it to CDRS component + "route_profile": false, // attaches RouteProfileID to RouteIDs which are sent as reply to asteristk agent authorization requests "asterisk_conns":[ // instantiate connections to multiple Asterisk servers { "address": "127.0.0.1:8088", @@ -730,6 +731,7 @@ const CGRATES_CFG_JSON = ` "empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined) "max_wait_connection": "2s", // maximum duration to wait for a connection to be retrieved from the pool "active_session_delimiter": ",", // delimiter for 'show channels' responses and requests + "route_profile": false, // attaches RouteProfileID to RouteIDs which are sent as reply to freeswitch agent authorization requests "event_socket_conns":[ // instantiate connections to multiple FreeSWITCH servers { "address": "127.0.0.1:8021", // FreeSWITCH server address and port @@ -748,6 +750,7 @@ const CGRATES_CFG_JSON = ` "sessions_conns": ["*birpc_internal"], "create_cdr": false, // create CDR out of events and sends them to CDRS component "timezone": "", // timezone of the Kamailio server + "route_profile": false, // attaches RouteProfileID to RouteIDs which are sent as reply to kamailio agent authorization requests "evapi_conns":[ // instantiate connections to multiple Kamailio servers { "address": "127.0.0.1:8448", diff --git a/config/config_json_test.go b/config/config_json_test.go index a49d9b4fb..b65ac59c7 100644 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -994,6 +994,7 @@ func TestFsAgentJsonCfg(t *testing.T) { SessionSConns: &[]string{rpcclient.BiRPCInternal}, SubscribePark: utils.BoolPointer(true), CreateCDR: utils.BoolPointer(false), + RouteProfile: utils.BoolPointer(false), ExtraFields: &[]string{}, LowBalanceAnnFile: utils.StringPointer(""), EmptyBalanceContext: utils.StringPointer(""), @@ -1026,6 +1027,7 @@ func TestKamAgentJsonCfg(t *testing.T) { Enabled: utils.BoolPointer(false), Sessions_conns: &[]string{rpcclient.BiRPCInternal}, Create_cdr: utils.BoolPointer(false), + Route_profile: utils.BoolPointer(false), Evapi_conns: &[]*KamConnJsonCfg{ { Address: utils.StringPointer("127.0.0.1:8448"), @@ -1052,6 +1054,7 @@ func TestAsteriskAgentJsonCfg(t *testing.T) { Enabled: utils.BoolPointer(false), Sessions_conns: &[]string{rpcclient.BiRPCInternal}, Create_cdr: utils.BoolPointer(false), + Route_profile: utils.BoolPointer(false), Asterisk_conns: &[]*AstConnJsonCfg{ { Address: utils.StringPointer("127.0.0.1:8088"), diff --git a/config/config_test.go b/config/config_test.go index 5e10f9f36..5172fd1e5 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -653,6 +653,7 @@ func TestCgrCfgJSONDefaultsFsAgentConfig(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)}, SubscribePark: true, CreateCDR: false, + RouteProfile: false, ExtraFields: RSRParsers{}, EmptyBalanceContext: "", EmptyBalanceAnnFile: "", @@ -677,6 +678,7 @@ func TestCgrCfgJSONDefaultsKamAgentConfig(t *testing.T) { Enabled: false, SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)}, CreateCdr: false, + RouteProfile: false, EvapiConns: []*KamConnCfg{{ Address: "127.0.0.1:8448", Reconnects: 5, @@ -693,6 +695,7 @@ func TestCgrCfgJSONDefaultssteriskAgentCfg(t *testing.T) { Enabled: false, SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)}, CreateCDR: false, + RouteProfile: false, AsteriskConns: []*AsteriskConnCfg{ {Address: "127.0.0.1:8088", User: "cgrates", Password: "CGRateS.org", @@ -2028,6 +2031,7 @@ func TestFsAgentConfig(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)}, SubscribePark: true, CreateCDR: false, + RouteProfile: false, LowBalanceAnnFile: "", EmptyBalanceAnnFile: "", EmptyBalanceContext: "", @@ -2056,6 +2060,7 @@ func TestKamAgentConfig(t *testing.T) { Enabled: false, SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)}, CreateCdr: false, + RouteProfile: false, EvapiConns: []*KamConnCfg{{Address: "127.0.0.1:8448", Reconnects: 5, Alias: ""}}, Timezone: "", } @@ -2071,6 +2076,7 @@ func TestAsteriskAgentConfig(t *testing.T) { Enabled: false, SessionSConns: []string{utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS)}, CreateCDR: false, + RouteProfile: false, AsteriskConns: []*AsteriskConnCfg{{ Alias: "", Address: "127.0.0.1:8088", @@ -3870,6 +3876,7 @@ func TestV1GetConfigFsAgent(t *testing.T) { utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal}, utils.SubscribeParkCfg: true, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.ExtraFieldsCfg: "", utils.LowBalanceAnnFileCfg: "", utils.EmptyBalanceContextCfg: "", @@ -3902,6 +3909,7 @@ func TestV1GetConfigKamailioAgent(t *testing.T) { utils.EnabledCfg: false, utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal}, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.TimezoneCfg: "", utils.EvapiConnsCfg: []map[string]any{ { @@ -3928,6 +3936,7 @@ func TestV1GetConfigAsteriskAgent(t *testing.T) { utils.EnabledCfg: false, utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal}, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.AsteriskConnsCfg: []map[string]any{ { utils.AliasCfg: "", @@ -4987,7 +4996,7 @@ func TestV1GetConfigAsJSONSessionS(t *testing.T) { func TestV1GetConfigAsJSONFreeSwitchAgent(t *testing.T) { var reply string - expected := `{"freeswitch_agent":{"active_session_delimiter":",","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,"reply_timeout":"1m0s"}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true}}` + expected := `{"freeswitch_agent":{"active_session_delimiter":",","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,"reply_timeout":"1m0s"}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","route_profile":false,"sessions_conns":["*birpc_internal"],"subscribe_park":true}}` cfgCgr := NewDefaultCGRConfig() if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: FreeSWITCHAgentJSN}, &reply); err != nil { t.Error(err) @@ -4998,7 +5007,7 @@ func TestV1GetConfigAsJSONFreeSwitchAgent(t *testing.T) { func TestV1GetConfigAsJSONFKamailioAgent(t *testing.T) { var reply string - expected := `{"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":""}}` + expected := `{"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"route_profile":false,"sessions_conns":["*birpc_internal"],"timezone":""}}` cfgCgr := NewDefaultCGRConfig() if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: KamailioAgentJSN}, &reply); err != nil { t.Error(err) @@ -5009,7 +5018,7 @@ func TestV1GetConfigAsJSONFKamailioAgent(t *testing.T) { func TestV1GetConfigAsJSONAsteriskAgent(t *testing.T) { var reply string - expected := `{"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"]}}` + expected := `{"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,"route_profile":false,"sessions_conns":["*birpc_internal"]}}` cfgCgr := NewDefaultCGRConfig() if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Section: AsteriskAgentJSN}, &reply); err != nil { t.Error(err) @@ -5389,7 +5398,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":{"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,"exists_indexed_fields":[],"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_ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*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},"*ip_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*radius_packets":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*ranking_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"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"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*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},"*trend_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"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":[],"compress_stored_cost":false,"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,"exists_indexed_fields":[],"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},"*ip_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"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},"*sessions_backup":{"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},"*trend_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/datadb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/datadb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_failed_dir":"","replication_filtered":false,"replication_interval":"0s"},"diameter_agent":{"asr_template":"","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"],"stats_conns":[],"synced_conn_requests":false,"thresholds_conns":[],"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"prevent_loop":false,"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"stats_conns":[],"thresholds_conns":[],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*amqp_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*amqpv1_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*els":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*kafka_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*nats_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*s3_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*sql":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*sqs_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false}},"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","metrics_reset_schedule":"","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"concurrent_events":1,"ees_conns":[],"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","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","start_delay":"0","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"],"stats_conns":[],"thresholds_conns":[]},"filters":{"apiers_conns":[],"rankings_conns":[],"resources_conns":[],"stats_conns":[],"trends_conns":[]},"freeswitch_agent":{"active_session_delimiter":",","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,"reply_timeout":"1m0s"}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"caching_delay":"0","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","pprof_path":"/debug/pprof/","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"ips":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"0s","string_indexed_fields":null,"suffix_indexed_fields":[]},"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":"TTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.5"},{"path":"AddressPool","tag":"AddressPool","type":"*variable","value":"~*req.6"},{"path":"Allocation","tag":"Allocation","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"}],"file_name":"IPs.csv","flags":null,"type":"*ips"},{"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":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","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":{"mongoConnScheme":"mongodb","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":null},"prometheus_agent":{"collect_go_metrics":false,"collect_process_metrics":false,"cores_conns":null,"enabled":false,"path":"/prometheus","stat_queue_ids":null,"stats_conns":null},"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"coa_template":"*coa","dmr_template":"*dmr","enabled":false,"listeners":[{"acct_address":"127.0.0.1:1813","auth_address":"127.0.0.1:1812","network":"udp"}],"request_processors":[],"requests_cache_key":"","sessions_conns":["*internal"],"stats_conns":[],"thresholds_conns":[]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"fallback_depth":3,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"sessions_conns":[],"stats_conns":[],"thresholds_conns":[]},"rankings":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"exists_indexed_fields":[],"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,"exists_indexed_fields":[],"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":[]},"sentrypeer":{"Audience":"https://sentrypeer.com/api","ClientID":"","ClientSecret":"","GrantType":"client_credentials","IpUrl":"https://sentrypeer.com/api/ip-addresses","NumberUrl":"https://sentrypeer.com/api/phone-numbers","TokenURL":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"alterable_fields":[],"attributes_conns":[],"backup_interval":"0","cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":2,"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","stale_chan_max_extra_usage":"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"],"stats_conns":[],"thresholds_conns":[],"timezone":""},"stats":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"exists_indexed_fields":[],"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":"CGRateS.org","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_ips":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rankings":{"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},"*tp_trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/stordb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/stordb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","pgSchema":"","sqlConnMaxLifetime":"0s","sqlLogLevel":3,"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"}],"*coa":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Filter-Id","tag":"Filter-Id","type":"*variable","value":"~*req.CustomFilter"}],"*dmr":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Reply-Message","tag":"Reply-Message","type":"*variable","value":"~*req.DisconnectCause"}],"*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":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"exists_indexed_fields":[],"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},"trends":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","store_uncompressed_limit":0,"thresholds_conns":[]}}` + expected := `{"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","enabled":false,"index_type":"*scorch","ttl":"24h0m0s"},"apiban":{"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,"route_profile":false,"sessions_conns":["*birpc_internal"]},"attributes":{"any_context":true,"apiers_conns":[],"enabled":false,"exists_indexed_fields":[],"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_ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*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},"*ip_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*radius_packets":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*ranking_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"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"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*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},"*trend_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"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":[],"compress_stored_cost":false,"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,"exists_indexed_fields":[],"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},"*ip_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"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},"*sessions_backup":{"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},"*trend_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/datadb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/datadb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_failed_dir":"","replication_filtered":false,"replication_interval":"0s"},"diameter_agent":{"asr_template":"","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"],"stats_conns":[],"synced_conn_requests":false,"thresholds_conns":[],"vendor_id":0},"dispatchers":{"any_subsystem":true,"attributes_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"prefix_indexed_fields":[],"prevent_loop":false,"suffix_indexed_fields":[]},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"stats_conns":[],"thresholds_conns":[],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*amqp_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*amqpv1_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*els":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*file_csv":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*kafka_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*nats_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*s3_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*sql":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*sqs_json_map":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false}},"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","metrics_reset_schedule":"","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"ers":{"concurrent_events":1,"ees_conns":[],"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","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","start_delay":"0","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"],"stats_conns":[],"thresholds_conns":[]},"filters":{"apiers_conns":[],"rankings_conns":[],"resources_conns":[],"stats_conns":[],"trends_conns":[]},"freeswitch_agent":{"active_session_delimiter":",","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,"reply_timeout":"1m0s"}],"extra_fields":"","low_balance_ann_file":"","max_wait_connection":"2s","route_profile":false,"sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"caching_delay":"0","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","pprof_path":"/debug/pprof/","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"ips":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"opts":{"*units":1,"*usageID":""},"prefix_indexed_fields":[],"store_interval":"0s","string_indexed_fields":null,"suffix_indexed_fields":[]},"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"route_profile":false,"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":"TTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.5"},{"path":"AddressPool","tag":"AddressPool","type":"*variable","value":"~*req.6"},{"path":"Allocation","tag":"Allocation","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"Weight","tag":"Weight","type":"*variable","value":"~*req.9"}],"file_name":"IPs.csv","flags":null,"type":"*ips"},{"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":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"0s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","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":{"mongoConnScheme":"mongodb","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":null},"prometheus_agent":{"collect_go_metrics":false,"collect_process_metrics":false,"cores_conns":null,"enabled":false,"path":"/prometheus","stat_queue_ids":null,"stats_conns":null},"radius_agent":{"client_dictionaries":{"*default":["/usr/share/cgrates/radius/dict/"]},"client_secrets":{"*default":"CGRateS.org"},"coa_template":"*coa","dmr_template":"*dmr","enabled":false,"listeners":[{"acct_address":"127.0.0.1:1813","auth_address":"127.0.0.1:1812","network":"udp"}],"request_processors":[],"requests_cache_key":"","sessions_conns":["*internal"],"stats_conns":[],"thresholds_conns":[]},"rals":{"balance_rating_subject":{"*any":"*zero1ns","*voice":"*zero1s"},"enabled":false,"fallback_depth":3,"max_computed_usage":{"*any":"189h0m0s","*data":"107374182400","*mms":"10000","*sms":"10000","*voice":"72h0m0s"},"max_increments":1000000,"remove_expired":true,"rp_subject_prefix_matching":false,"sessions_conns":[],"stats_conns":[],"thresholds_conns":[]},"rankings":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","thresholds_conns":[]},"registrarc":{"dispatchers":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]},"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"exists_indexed_fields":[],"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,"exists_indexed_fields":[],"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":[]},"sentrypeer":{"Audience":"https://sentrypeer.com/api","ClientID":"","ClientSecret":"","GrantType":"client_credentials","IpUrl":"https://sentrypeer.com/api/ip-addresses","NumberUrl":"https://sentrypeer.com/api/phone-numbers","TokenURL":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"alterable_fields":[],"attributes_conns":[],"backup_interval":"0","cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":2,"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","stale_chan_max_extra_usage":"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"],"stats_conns":[],"thresholds_conns":[],"timezone":""},"stats":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"exists_indexed_fields":[],"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":"CGRateS.org","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_ips":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*tp_rankings":{"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},"*tp_trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/stordb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/stordb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","pgSchema":"","sqlConnMaxLifetime":"0s","sqlLogLevel":3,"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"}],"*coa":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Filter-Id","tag":"Filter-Id","type":"*variable","value":"~*req.CustomFilter"}],"*dmr":[{"path":"*radDAReq.User-Name","tag":"User-Name","type":"*variable","value":"~*oreq.User-Name"},{"path":"*radDAReq.NAS-IP-Address","tag":"NAS-IP-Address","type":"*variable","value":"~*oreq.NAS-IP-Address"},{"path":"*radDAReq.Acct-Session-Id","tag":"Acct-Session-Id","type":"*variable","value":"~*oreq.Acct-Session-Id"},{"path":"*radDAReq.Reply-Message","tag":"Reply-Message","type":"*variable","value":"~*req.DisconnectCause"}],"*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":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"exists_indexed_fields":[],"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},"trends":{"ees_conns":[],"ees_exporter_ids":[],"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","store_uncompressed_limit":0,"thresholds_conns":[]}}` if err != nil { t.Fatal(err) } diff --git a/config/kamagentcfg.go b/config/kamagentcfg.go index 68df172e9..854c3f7b8 100644 --- a/config/kamagentcfg.go +++ b/config/kamagentcfg.go @@ -90,6 +90,7 @@ type KamAgentCfg struct { CreateCdr bool EvapiConns []*KamConnCfg Timezone string + RouteProfile bool } func (ka *KamAgentCfg) loadFromJSONCfg(jsnCfg *KamAgentJsonCfg) error { @@ -123,15 +124,19 @@ func (ka *KamAgentCfg) loadFromJSONCfg(jsnCfg *KamAgentJsonCfg) error { if jsnCfg.Timezone != nil { ka.Timezone = *jsnCfg.Timezone } + if jsnCfg.Route_profile != nil { + ka.RouteProfile = *jsnCfg.Route_profile + } return nil } // AsMapInterface returns the config as a map[string]any func (ka *KamAgentCfg) AsMapInterface() (initialMP map[string]any) { initialMP = map[string]any{ - utils.EnabledCfg: ka.Enabled, - utils.CreateCdrCfg: ka.CreateCdr, - utils.TimezoneCfg: ka.Timezone, + utils.EnabledCfg: ka.Enabled, + utils.CreateCdrCfg: ka.CreateCdr, + utils.TimezoneCfg: ka.Timezone, + utils.RouteProfileCfg: ka.RouteProfile, } if ka.EvapiConns != nil { evapiConns := make([]map[string]any, len(ka.EvapiConns)) @@ -158,9 +163,10 @@ func (ka *KamAgentCfg) AsMapInterface() (initialMP map[string]any) { // Clone returns a deep copy of KamAgentCfg func (ka KamAgentCfg) Clone() (cln *KamAgentCfg) { cln = &KamAgentCfg{ - Enabled: ka.Enabled, - CreateCdr: ka.CreateCdr, - Timezone: ka.Timezone, + Enabled: ka.Enabled, + CreateCdr: ka.CreateCdr, + Timezone: ka.Timezone, + RouteProfile: ka.RouteProfile, } if ka.SessionSConns != nil { cln.SessionSConns = make([]string, len(ka.SessionSConns)) diff --git a/config/kamagentcfg_test.go b/config/kamagentcfg_test.go index 6f4ede563..505f5af6e 100644 --- a/config/kamagentcfg_test.go +++ b/config/kamagentcfg_test.go @@ -30,6 +30,7 @@ func TestKamAgentCfgloadFromJsonCfg(t *testing.T) { Enabled: utils.BoolPointer(true), Sessions_conns: &[]string{"*internal"}, Create_cdr: utils.BoolPointer(true), + Route_profile: utils.BoolPointer(true), Evapi_conns: &[]*KamConnJsonCfg{ { Alias: utils.StringPointer("randomAlias"), @@ -43,6 +44,7 @@ func TestKamAgentCfgloadFromJsonCfg(t *testing.T) { Enabled: true, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, CreateCdr: true, + RouteProfile: true, EvapiConns: []*KamConnCfg{{Address: "127.0.0.1:8448", Reconnects: 10, Alias: "randomAlias"}}, Timezone: "Local", } @@ -99,6 +101,7 @@ func TestKamAgentCfgAsMapInterface(t *testing.T) { "kamailio_agent": { "sessions_conns": ["*birpc_internal", "*conn1","*conn2", "*internal"], "create_cdr": true, + "route_profile": true, "timezone": "UTC", "evapi_conns":[ {"address": "127.0.0.1:8448", "reconnects": 5, "alias": ""} @@ -109,6 +112,7 @@ func TestKamAgentCfgAsMapInterface(t *testing.T) { utils.EnabledCfg: false, utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal, "*conn1", "*conn2", utils.MetaInternal}, utils.CreateCdrCfg: true, + utils.RouteProfileCfg: true, utils.TimezoneCfg: "UTC", utils.EvapiConnsCfg: []map[string]any{ {utils.AddressCfg: "127.0.0.1:8448", utils.ReconnectsCfg: 5, utils.MaxReconnectIntervalCfg: "0s", utils.AliasCfg: ""}, @@ -129,6 +133,7 @@ func TestKamAgentCfgAsMapInterface1(t *testing.T) { utils.EnabledCfg: false, utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal}, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.TimezoneCfg: "", utils.EvapiConnsCfg: []map[string]any{ {utils.AddressCfg: "127.0.0.1:8448", utils.ReconnectsCfg: 5, utils.MaxReconnectIntervalCfg: "0s", utils.AliasCfg: ""}, @@ -146,6 +151,7 @@ func TestKamAgentCfgClone(t *testing.T) { Enabled: true, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, CreateCdr: true, + RouteProfile: true, EvapiConns: []*KamConnCfg{{Address: "127.0.0.1:8448", Reconnects: 10, Alias: "randomAlias"}}, Timezone: "Local", } diff --git a/config/libconfig_json.go b/config/libconfig_json.go index fb2afb085..eaf4bad16 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -452,6 +452,7 @@ type FreeswitchAgentJsonCfg struct { EmptyBalanceAnnFile *string `json:"empty_balance_ann_file"` ActiveSessionDelimiter *string `json:"active_session_delimiter"` MaxWaitConnection *string `json:"max_wait_connection"` + RouteProfile *bool `json:"route_profile"` EventSocketConns *[]*FsConnJsonCfg `json:"event_socket_conns"` } @@ -502,6 +503,7 @@ type AsteriskAgentJsonCfg struct { Enabled *bool Sessions_conns *[]string Create_cdr *bool + Route_profile *bool Asterisk_conns *[]*AstConnJsonCfg } @@ -527,6 +529,7 @@ type KamAgentJsonCfg struct { Create_cdr *bool Evapi_conns *[]*KamConnJsonCfg Timezone *string + Route_profile *bool } // Represents one connection instance towards Kamailio diff --git a/config/sessionscfg.go b/config/sessionscfg.go index 68eff79f7..10efec693 100644 --- a/config/sessionscfg.go +++ b/config/sessionscfg.go @@ -588,6 +588,7 @@ type FsAgentCfg struct { EmptyBalanceAnnFile string ActiveSessionDelimiter string MaxWaitConnection time.Duration + RouteProfile bool EventSocketConns []*FsConnCfg } @@ -616,6 +617,9 @@ func (fscfg *FsAgentCfg) loadFromJSONCfg(jsnCfg *FreeswitchAgentJsonCfg) error { if jsnCfg.CreateCDR != nil { fscfg.CreateCDR = *jsnCfg.CreateCDR } + if jsnCfg.RouteProfile != nil { + fscfg.RouteProfile = *jsnCfg.RouteProfile + } if jsnCfg.ExtraFields != nil { if fscfg.ExtraFields, err = NewRSRParsersFromSlice(*jsnCfg.ExtraFields); err != nil { return err @@ -655,6 +659,7 @@ func (fscfg *FsAgentCfg) AsMapInterface(separator string) (initialMP map[string] utils.EnabledCfg: fscfg.Enabled, utils.SubscribeParkCfg: fscfg.SubscribePark, utils.CreateCdrCfg: fscfg.CreateCDR, + utils.RouteProfileCfg: fscfg.RouteProfile, utils.LowBalanceAnnFileCfg: fscfg.LowBalanceAnnFile, utils.EmptyBalanceContextCfg: fscfg.EmptyBalanceContext, utils.EmptyBalanceAnnFileCfg: fscfg.EmptyBalanceAnnFile, @@ -697,6 +702,7 @@ func (fscfg FsAgentCfg) Clone() (cln *FsAgentCfg) { Enabled: fscfg.Enabled, SubscribePark: fscfg.SubscribePark, CreateCDR: fscfg.CreateCDR, + RouteProfile: fscfg.RouteProfile, ExtraFields: fscfg.ExtraFields.Clone(), LowBalanceAnnFile: fscfg.LowBalanceAnnFile, EmptyBalanceContext: fscfg.EmptyBalanceContext, @@ -798,6 +804,7 @@ type AsteriskAgentCfg struct { Enabled bool SessionSConns []string CreateCDR bool + RouteProfile bool AsteriskConns []*AsteriskConnCfg } @@ -822,6 +829,9 @@ func (aCfg *AsteriskAgentCfg) loadFromJSONCfg(jsnCfg *AsteriskAgentJsonCfg) (err if jsnCfg.Create_cdr != nil { aCfg.CreateCDR = *jsnCfg.Create_cdr } + if jsnCfg.Route_profile != nil { + aCfg.RouteProfile = *jsnCfg.Route_profile + } if jsnCfg.Asterisk_conns != nil { aCfg.AsteriskConns = make([]*AsteriskConnCfg, len(*jsnCfg.Asterisk_conns)) @@ -836,8 +846,9 @@ func (aCfg *AsteriskAgentCfg) loadFromJSONCfg(jsnCfg *AsteriskAgentJsonCfg) (err // AsMapInterface returns the config as a map[string]any func (aCfg *AsteriskAgentCfg) AsMapInterface() (initialMP map[string]any) { initialMP = map[string]any{ - utils.EnabledCfg: aCfg.Enabled, - utils.CreateCDRCfg: aCfg.CreateCDR, + utils.EnabledCfg: aCfg.Enabled, + utils.CreateCDRCfg: aCfg.CreateCDR, + utils.RouteProfileCfg: aCfg.RouteProfile, } if aCfg.AsteriskConns != nil { conns := make([]map[string]any, len(aCfg.AsteriskConns)) @@ -864,8 +875,9 @@ func (aCfg *AsteriskAgentCfg) AsMapInterface() (initialMP map[string]any) { // Clone returns a deep copy of AsteriskAgentCfg func (aCfg AsteriskAgentCfg) Clone() (cln *AsteriskAgentCfg) { cln = &AsteriskAgentCfg{ - Enabled: aCfg.Enabled, - CreateCDR: aCfg.CreateCDR, + Enabled: aCfg.Enabled, + CreateCDR: aCfg.CreateCDR, + RouteProfile: aCfg.RouteProfile, } if aCfg.SessionSConns != nil { cln.SessionSConns = make([]string, len(aCfg.SessionSConns)) diff --git a/config/sessionscfg_test.go b/config/sessionscfg_test.go index 625e8f98e..4898c3eb0 100644 --- a/config/sessionscfg_test.go +++ b/config/sessionscfg_test.go @@ -31,6 +31,7 @@ func TestFsAgentCfgloadFromJsonCfg1(t *testing.T) { fsAgentJsnCfg := &FreeswitchAgentJsonCfg{ Enabled: utils.BoolPointer(true), CreateCDR: utils.BoolPointer(true), + RouteProfile: utils.BoolPointer(true), SubscribePark: utils.BoolPointer(true), EventSocketConns: &[]*FsConnJsonCfg{ { @@ -49,6 +50,7 @@ func TestFsAgentCfgloadFromJsonCfg1(t *testing.T) { eFsAgentConfig := &FsAgentCfg{ Enabled: true, CreateCDR: true, + RouteProfile: true, SubscribePark: true, EventSocketConns: []*FsConnCfg{ {Address: "1.2.3.4:8021", Password: "ClueCon", Reconnects: 5, ReplyTimeout: 5 * time.Second, Alias: "1.2.3.4:8021"}, @@ -502,6 +504,7 @@ func TestFsAgentCfgloadFromJsonCfgCase1(t *testing.T) { Enabled: utils.BoolPointer(true), SessionSConns: &[]string{utils.MetaInternal}, CreateCDR: utils.BoolPointer(true), + RouteProfile: utils.BoolPointer(true), SubscribePark: utils.BoolPointer(true), LowBalanceAnnFile: utils.StringPointer("randomFile"), EmptyBalanceAnnFile: utils.StringPointer("randomEmptyFile"), @@ -524,6 +527,7 @@ func TestFsAgentCfgloadFromJsonCfgCase1(t *testing.T) { SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, SubscribePark: true, CreateCDR: true, + RouteProfile: true, LowBalanceAnnFile: "randomFile", EmptyBalanceAnnFile: "randomEmptyFile", EmptyBalanceContext: "randomEmptyContext", @@ -579,6 +583,7 @@ func TestFsAgentCfgAsMapInterfaceCase1(t *testing.T) { utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal}, utils.SubscribeParkCfg: true, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.ExtraFieldsCfg: "", utils.LowBalanceAnnFileCfg: "", utils.EmptyBalanceContextCfg: "", @@ -610,6 +615,7 @@ func TestFsAgentCfgAsMapInterfaceCase2(t *testing.T) { "sessions_conns": ["*birpc_internal", "*conn1","*conn2"], "subscribe_park": false, "create_cdr": true, + "route_profile": true, "max_wait_connection": "7s", "active_session_delimiter": "\tsep\t", "event_socket_conns":[ @@ -621,6 +627,7 @@ func TestFsAgentCfgAsMapInterfaceCase2(t *testing.T) { utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal, "*conn1", "*conn2"}, utils.SubscribeParkCfg: false, utils.CreateCdrCfg: true, + utils.RouteProfileCfg: true, utils.ExtraFieldsCfg: "", utils.LowBalanceAnnFileCfg: "", utils.EmptyBalanceContextCfg: "", @@ -659,6 +666,7 @@ func TestFsAgentCfgAsMapInterfaceCase3(t *testing.T) { utils.SessionSConnsCfg: []string{utils.MetaInternal}, utils.SubscribeParkCfg: true, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.ExtraFieldsCfg: "randomFields", utils.LowBalanceAnnFileCfg: "", utils.EmptyBalanceContextCfg: "", @@ -750,6 +758,7 @@ func TestAsteriskAgentCfgloadFromJsonCfg(t *testing.T) { Enabled: utils.BoolPointer(true), Sessions_conns: &[]string{utils.MetaInternal}, Create_cdr: utils.BoolPointer(true), + Route_profile: utils.BoolPointer(true), Asterisk_conns: &[]*AstConnJsonCfg{ { Alias: utils.StringPointer("127.0.0.1:8448"), @@ -765,6 +774,7 @@ func TestAsteriskAgentCfgloadFromJsonCfg(t *testing.T) { Enabled: true, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)}, CreateCDR: true, + RouteProfile: true, AsteriskConns: []*AsteriskConnCfg{{ Alias: "127.0.0.1:8448", Address: "127.0.0.1:8088", @@ -792,6 +802,7 @@ func TestAsteriskAgentCfgAsMapInterface(t *testing.T) { utils.EnabledCfg: false, utils.SessionSConnsCfg: []string{utils.MetaInternal}, utils.CreateCdrCfg: false, + utils.RouteProfileCfg: false, utils.AsteriskConnsCfg: []map[string]any{ {utils.AliasCfg: "", utils.AddressCfg: "127.0.0.1:8088", utils.UserCf: "cgrates", utils.Password: "CGRateS.org", utils.ConnectAttemptsCfg: 3, utils.ReconnectsCfg: 5, utils.MaxReconnectIntervalCfg: "0s"}, }, @@ -809,6 +820,7 @@ func TestAsteriskAgentCfgAsMapInterface1(t *testing.T) { "enabled": true, "sessions_conns": ["*birpc_internal", "*conn1","*conn2"], "create_cdr": true, + "route_profile": true, "asterisk_conns":[ {"address": "127.0.0.1:8089","connect_attempts": 5,"reconnects": 8} ], @@ -818,6 +830,7 @@ func TestAsteriskAgentCfgAsMapInterface1(t *testing.T) { utils.EnabledCfg: true, utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal, "*conn1", "*conn2"}, utils.CreateCdrCfg: true, + utils.RouteProfileCfg: true, utils.AsteriskConnsCfg: []map[string]any{ {utils.AliasCfg: "", utils.AddressCfg: "127.0.0.1:8089", utils.UserCf: "cgrates", utils.Password: "CGRateS.org", utils.ConnectAttemptsCfg: 5, utils.ReconnectsCfg: 8, utils.MaxReconnectIntervalCfg: "0s"}, }, @@ -873,6 +886,7 @@ func TestAsteriskAgentCfgClone(t *testing.T) { Enabled: true, SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"}, CreateCDR: true, + RouteProfile: true, AsteriskConns: []*AsteriskConnCfg{{ Alias: "127.0.0.1:8448", Address: "127.0.0.1:8088", @@ -898,6 +912,7 @@ func TestFsAgentCfgClone(t *testing.T) { ban := &FsAgentCfg{ Enabled: true, CreateCDR: true, + RouteProfile: true, SubscribePark: true, EmptyBalanceAnnFile: "file", EmptyBalanceContext: "context", diff --git a/data/conf/samples/dynamic_account_threshold/cgrates.json b/data/conf/samples/dynamic_account_threshold/cgrates.json index 424f3103c..0694f5089 100644 --- a/data/conf/samples/dynamic_account_threshold/cgrates.json +++ b/data/conf/samples/dynamic_account_threshold/cgrates.json @@ -19,7 +19,8 @@ "schedulers": { "enabled": true, - "dynaprepaid_actionplans": ["DYNA_ACC"] + "dynaprepaid_actionplans": ["DYNA_ACC"], + "thresholds_conns": ["*localhost"] }, "chargers": { diff --git a/engine/action.go b/engine/action.go index cda1eda80..c39337a19 100644 --- a/engine/action.go +++ b/engine/action.go @@ -1515,12 +1515,14 @@ func dynamicThreshold(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return utils.ErrUnsupportedFormat } if len(aISplit) > 0 && aISplit[0] != utils.EmptyString { - if err := thProf.ActivationInterval.ActivationTime.UnmarshalText([]byte(aISplit[0])); err != nil { - return err - } - if len(aISplit) == 2 { - if err := thProf.ActivationInterval.ExpiryTime.UnmarshalText([]byte(aISplit[1])); err != nil { + for i := range aISplit { + if timeParsed, err := utils.ParseTimeDetectLayout(aISplit[i], + config.CgrConfig().GeneralCfg().DefaultTimezone); err != nil { return err + } else if i == 0 { + thProf.ActivationInterval.ActivationTime = timeParsed + } else if i == 1 { + thProf.ActivationInterval.ExpiryTime = timeParsed } } } @@ -1648,12 +1650,14 @@ func dynamicStats(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return utils.ErrUnsupportedFormat } if len(aISplit) > 0 && aISplit[0] != utils.EmptyString { - if err := stQProf.ActivationInterval.ActivationTime.UnmarshalText([]byte(aISplit[0])); err != nil { - return err - } - if len(aISplit) == 2 { - if err := stQProf.ActivationInterval.ExpiryTime.UnmarshalText([]byte(aISplit[1])); err != nil { + for i := range aISplit { + if timeParsed, err := utils.ParseTimeDetectLayout(aISplit[i], + config.CgrConfig().GeneralCfg().DefaultTimezone); err != nil { return err + } else if i == 0 { + stQProf.ActivationInterval.ActivationTime = timeParsed + } else if i == 1 { + stQProf.ActivationInterval.ExpiryTime = timeParsed } } } @@ -1794,12 +1798,14 @@ func dynamicAttribute(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return utils.ErrUnsupportedFormat } if len(aISplit) > 0 && aISplit[0] != utils.EmptyString { - if err := attrP.ActivationInterval.ActivationTime.UnmarshalText([]byte(aISplit[0])); err != nil { - return err - } - if len(aISplit) == 2 { - if err := attrP.ActivationInterval.ExpiryTime.UnmarshalText([]byte(aISplit[1])); err != nil { + for i := range aISplit { + if timeParsed, err := utils.ParseTimeDetectLayout(aISplit[i], + config.CgrConfig().GeneralCfg().DefaultTimezone); err != nil { return err + } else if i == 0 { + attrP.ActivationInterval.ActivationTime = timeParsed + } else if i == 1 { + attrP.ActivationInterval.ExpiryTime = timeParsed } } } @@ -2046,6 +2052,7 @@ func dynamicActionPlanAccount(_ *Account, act *Action, _ Actions, _ *FilterS, ev // 14 BalanceBlocker: string // 15 BalanceDisabled: string // 16 Weight: float +// 17 Overwrite: bool // // Parameters are separated by ";" and must be provided in the specified order. func dynamicAction(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, @@ -2080,8 +2087,8 @@ func dynamicAction(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, } params = append(params, bildr.String()) // append last param left even if empty // Parse action parameters based on the predefined format. - if len(params) != 17 { - return fmt.Errorf("invalid number of parameters <%d> expected 17", len(params)) + if len(params) != 18 { + return fmt.Errorf("invalid number of parameters <%d> expected 18", len(params)) } // replace '&' with ';' before parsing to comply with TPAction fields that need ";" seperators params[3] = strings.ReplaceAll(params[3], utils.ANDSep, utils.InfieldSep) @@ -2109,6 +2116,14 @@ func dynamicAction(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return err } } + var overwrite bool + // populate Action's Overwrite + if params[17] != utils.EmptyString { + overwrite, err = strconv.ParseBool(params[17]) + if err != nil { + return err + } + } // populate action parameters ap := &utils.AttrSetActions{ ActionsId: params[0], @@ -2132,6 +2147,7 @@ func dynamicAction(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, Weight: weight, }, }, + Overwrite: overwrite, } // create the Action based on the populated parameters @@ -2247,12 +2263,14 @@ func dynamicFilter(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return utils.ErrUnsupportedFormat } if len(aISplit) > 0 && aISplit[0] != utils.EmptyString { - if err := fltr.ActivationInterval.ActivationTime.UnmarshalText([]byte(aISplit[0])); err != nil { - return err - } - if len(aISplit) == 2 { - if err := fltr.ActivationInterval.ExpiryTime.UnmarshalText([]byte(aISplit[1])); err != nil { + for i := range aISplit { + if timeParsed, err := utils.ParseTimeDetectLayout(aISplit[i], + config.CgrConfig().GeneralCfg().DefaultTimezone); err != nil { return err + } else if i == 0 { + fltr.ActivationInterval.ActivationTime = timeParsed + } else if i == 1 { + fltr.ActivationInterval.ExpiryTime = timeParsed } } } @@ -2314,87 +2332,165 @@ func dynamicRoute(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return err } } - // Prepare request arguments based on provided parameters. + // Take only the string after @, for cases when the RouteProfileID is gotten from a switch agents event + routeFieldParts := strings.Split(params[1], "@") + routeProfileFound := new(RouteProfile) + if len(routeFieldParts) > 2 { + return fmt.Errorf("more than 1 \"@\" character for RouteProfileID: <%s>", params[1]) + } else if len(routeFieldParts) > 1 { + params[1] = routeFieldParts[1] + if err := connMgr.Call(context.Background(), connCfg.ConnIDs, + utils.APIerSv1GetRouteProfile, &utils.TenantID{Tenant: utils.FirstNonEmpty(cgrEv.Tenant, + config.CgrConfig().GeneralCfg().DefaultTenant), ID: params[1]}, + &routeProfileFound); err != nil && err.Error() != utils.ErrNotFound.Error() { + return err + } + } + // Prepare request arguments based on provided parameters. If any param is left empty, + // the field corresponding to it will be populated by the routeProfileFound field if it exists route := &RouteWithAPIOpts{ RouteProfile: &RouteProfile{ - Tenant: params[0], + Tenant: utils.FirstNonEmpty(params[0], routeProfileFound.Tenant), ID: params[1], ActivationInterval: &utils.ActivationInterval{}, // avoid reaching inside a nil pointer - Sorting: params[4], - Routes: []*Route{ - { - ID: params[6], - RouteParameters: params[14], - }, - }, + Sorting: utils.FirstNonEmpty(params[4], routeProfileFound.Sorting), }, APIOpts: make(map[string]any), } - // populate Route's FilterIDs + // populate RouteProfile's FilterIDs if params[2] != utils.EmptyString { route.FilterIDs = strings.Split(params[2], utils.ANDSep) + } else { + route.FilterIDs = routeProfileFound.FilterIDs } - // populate Route's ActivationInterval + // populate RouteProfile's ActivationInterval aISplit := strings.Split(params[3], utils.ANDSep) if len(aISplit) > 2 { return utils.ErrUnsupportedFormat } if len(aISplit) > 0 && aISplit[0] != utils.EmptyString { - if err := route.ActivationInterval.ActivationTime.UnmarshalText([]byte(aISplit[0])); err != nil { - return err - } - if len(aISplit) == 2 { - if err := route.ActivationInterval.ExpiryTime.UnmarshalText([]byte(aISplit[1])); err != nil { + for i := range aISplit { + if timeParsed, err := utils.ParseTimeDetectLayout(aISplit[i], + config.CgrConfig().GeneralCfg().DefaultTimezone); err != nil { return err + } else if i == 0 { + route.ActivationInterval.ActivationTime = timeParsed + } else if i == 1 { + route.ActivationInterval.ExpiryTime = timeParsed } } + } else { + route.ActivationInterval = routeProfileFound.ActivationInterval } - // populate Route's SortingParameters + // populate RouteProfile's SortingParameters if params[5] != utils.EmptyString { route.SortingParameters = strings.Split(params[5], utils.ANDSep) + } else { + route.SortingParameters = routeProfileFound.SortingParameters } - // populate Route's RouteFilterIDs - if params[7] != utils.EmptyString { - route.Routes[0].FilterIDs = strings.Split(params[7], utils.ANDSep) - } - // populate Route's RouteAccountIDs - if params[8] != utils.EmptyString { - route.Routes[0].AccountIDs = strings.Split(params[8], utils.ANDSep) - } - // populate Route's RouteRatingPlanIDs - if params[9] != utils.EmptyString { - route.Routes[0].RatingPlanIDs = strings.Split(params[9], utils.ANDSep) - } - // populate Route's RouteResourceIDs - if params[10] != utils.EmptyString { - route.Routes[0].ResourceIDs = strings.Split(params[10], utils.ANDSep) - } - // populate Route's RouteStatIDs - if params[11] != utils.EmptyString { - route.Routes[0].StatIDs = strings.Split(params[11], utils.ANDSep) - } - // populate Route's RouteWeight - if params[12] != utils.EmptyString { - route.Routes[0].Weight, err = strconv.ParseFloat(params[12], 64) - if err != nil { - return err + // populate RouteProfile's Routes + if params[6] != utils.EmptyString { + // keep the existing routes if routeProfile already existed, and modify the specified Routes by ID + var routeModified bool // if route doesnt exist in the found route Profile + for _, existingRoute := range routeProfileFound.Routes { + if existingRoute.ID == params[6] { // modify routes with ID + // populate RouteProfile's RouteFilterIDs + if params[7] != utils.EmptyString { + existingRoute.FilterIDs = strings.Split(params[7], utils.ANDSep) + } + // populate RouteProfile's RouteAccountIDs + if params[8] != utils.EmptyString { + existingRoute.AccountIDs = strings.Split(params[8], utils.ANDSep) + } + // populate RouteProfile's RouteRatingPlanIDs + if params[9] != utils.EmptyString { + existingRoute.RatingPlanIDs = strings.Split(params[9], utils.ANDSep) + } + // populate RouteProfile's RouteResourceIDs + if params[10] != utils.EmptyString { + existingRoute.ResourceIDs = strings.Split(params[10], utils.ANDSep) + } + // populate RouteProfile's RouteStatIDs + if params[11] != utils.EmptyString { + existingRoute.StatIDs = strings.Split(params[11], utils.ANDSep) + } + // populate RouteProfile's RouteWeight + if params[12] != utils.EmptyString { + existingRoute.Weight, err = strconv.ParseFloat(params[12], 64) + if err != nil { + return err + } + } + // populate RouteProfile's RouteBlocker + if params[13] != utils.EmptyString { + existingRoute.Blocker, err = strconv.ParseBool(params[13]) + if err != nil { + return err + } + } + if params[14] != utils.EmptyString { + existingRoute.RouteParameters = params[14] + } + routeModified = true + } + route.Routes = append(route.Routes, existingRoute) } - } - // populate Route's RouteBlocker - if params[13] != utils.EmptyString { - route.Routes[0].Blocker, err = strconv.ParseBool(params[13]) - if err != nil { - return err + if !routeModified { // if no existing routes were modified, append a new route + appendRoute := new(Route) // new route to be appended + // populate RouteProfile's RouteID + appendRoute.ID = params[6] + // populate RouteProfile's RouteFilterIDs + if params[7] != utils.EmptyString { + appendRoute.FilterIDs = strings.Split(params[7], utils.ANDSep) + } + // populate RouteProfile's RouteAccountIDs + if params[8] != utils.EmptyString { + appendRoute.AccountIDs = strings.Split(params[8], utils.ANDSep) + } + // populate RouteProfile's RouteRatingPlanIDs + if params[9] != utils.EmptyString { + appendRoute.RatingPlanIDs = strings.Split(params[9], utils.ANDSep) + } + // populate RouteProfile's RouteResourceIDs + if params[10] != utils.EmptyString { + appendRoute.ResourceIDs = strings.Split(params[10], utils.ANDSep) + } + // populate RouteProfile's RouteStatIDs + if params[11] != utils.EmptyString { + appendRoute.StatIDs = strings.Split(params[11], utils.ANDSep) + } + // populate RouteProfile's RouteWeight + if params[12] != utils.EmptyString { + appendRoute.Weight, err = strconv.ParseFloat(params[12], 64) + if err != nil { + return err + } + } + // populate RouteProfile's RouteBlocker + if params[13] != utils.EmptyString { + appendRoute.Blocker, err = strconv.ParseBool(params[13]) + if err != nil { + return err + } + } + // populate RouteProfile's RouteParameters + appendRoute.RouteParameters = params[14] + route.Routes = append(route.Routes, appendRoute) } + } else { + route.Routes = routeProfileFound.Routes } - // populate Route's Weight + + // populate RouteProfile's Weight if params[15] != utils.EmptyString { route.Weight, err = strconv.ParseFloat(params[15], 64) if err != nil { return err } + } else { + route.Weight = routeProfileFound.Weight } - // populate Route's APIOpts + // populate RouteProfile's APIOpts if params[16] != utils.EmptyString { if err := parseParamStringToMap(params[16], route.APIOpts); err != nil { return err @@ -2725,12 +2821,14 @@ func dynamicResource(_ *Account, act *Action, _ Actions, _ *FilterS, ev any, return utils.ErrUnsupportedFormat } if len(aISplit) > 0 && aISplit[0] != utils.EmptyString { - if err := rsc.ActivationInterval.ActivationTime.UnmarshalText([]byte(aISplit[0])); err != nil { - return err - } - if len(aISplit) == 2 { - if err := rsc.ActivationInterval.ExpiryTime.UnmarshalText([]byte(aISplit[1])); err != nil { + for i := range aISplit { + if timeParsed, err := utils.ParseTimeDetectLayout(aISplit[i], + config.CgrConfig().GeneralCfg().DefaultTimezone); err != nil { return err + } else if i == 0 { + rsc.ActivationInterval.ActivationTime = timeParsed + } else if i == 1 { + rsc.ActivationInterval.ExpiryTime = timeParsed } } } diff --git a/engine/actions_test.go b/engine/actions_test.go index dbd4efba4..f85432fd1 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -5057,12 +5057,12 @@ func TestDynamicThreshold(t *testing.T) { { name: "ActivationIntervalBadStringFail", extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;bad String;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "ActivationIntervalBadStringFail2", extraParams: "cgrates.org;THD_ACNT_1001;FLTR_ACNT_1001;2014-07-29T15:00:00Z&bad String;1;1;1s;false;10;ACT_LOG_WARNING;true;eeID1&eeID2;", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "MaxHitsFail", @@ -5304,12 +5304,12 @@ func TestDynamicStats(t *testing.T) { { name: "ActivationIntervalBadStringFail", extraParams: "cgrates.org;Stat_1;FLTR_STAT_1;bad String;100;10s;0;*acd&*tcd&*asr;Metric_FLTR;false;true;30;*none;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "ActivationIntervalBadStringFail2", extraParams: "cgrates.org;Stat_1;FLTR_STAT_1;2014-07-29T15:00:00Z&bad String;100;10s;0;*acd&*tcd&*asr;Metric_FLTR;false;true;30;*none;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "QueueLengthFail", @@ -5527,12 +5527,12 @@ func TestDynamicAttribute(t *testing.T) { { name: "ActivationIntervalBadStringFail", extraParams: "cgrates.org;Attr_1;*sessions&*chargers;FLTR_ATTR_1&FLTR_ATTR_2;bad String;AttrFltr_1&AttrFltr2;*req.Subject;*constant;SUPPLIER1;true;10;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "ActivationIntervalBadStringFail2", extraParams: "cgrates.org;Attr_1;*sessions&*chargers;FLTR_ATTR_1&FLTR_ATTR_2;2014-07-29T15:00:00Z&bad String;AttrFltr_1&AttrFltr2;*req.Subject;*constant;SUPPLIER1;true;10;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "AttributesValueFail", @@ -6043,7 +6043,7 @@ func TestDynamicActionAll(t *testing.T) { }, Overwrite: false, }, - extraParams: "Alter_Session_10;*alter_sessions;\fcgrates.org;*string:~*req.Account:1001;1;*radCoATemplate:mycoa;CustomFilter:mycustomvalue\f;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10", + extraParams: "Alter_Session_10;*alter_sessions;\fcgrates.org;*string:~*req.Account:1001;1;*radCoATemplate:mycoa;CustomFilter:mycustomvalue\f;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10;false", }, { name: "SuccessfulRequestWithDynamicPaths", @@ -6070,9 +6070,9 @@ func TestDynamicActionAll(t *testing.T) { Weight: 10, }, }, - Overwrite: false, + Overwrite: true, }, - extraParams: "CDR_Log_<~*req.Account>;*cdrlog;\f{\"Account\":\"<~*req.Account>\",\"RequestType\":\"*pseudoprepaid\",\"Subject\":\"DifferentThanAccount\", \"ToR\":\"~ActionType:s/^\\*(.*)$/did_$1/\"}\f;*string:~*req.Account:<~*req.Account>&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10", + extraParams: "CDR_Log_<~*req.Account>;*cdrlog;\f{\"Account\":\"<~*req.Account>\",\"RequestType\":\"*pseudoprepaid\",\"Subject\":\"DifferentThanAccount\", \"ToR\":\"~ActionType:s/^\\*(.*)$/did_$1/\"}\f;*string:~*req.Account:<~*req.Account>&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10;true", }, { name: "SuccessfulRequestEmptyFields", @@ -6085,31 +6085,31 @@ func TestDynamicActionAll(t *testing.T) { }, }, }, - extraParams: "DISABLE_ACC;*disable_account;;;;;;;;;;;;;;;", + extraParams: "DISABLE_ACC;*disable_account;;;;;;;;;;;;;;;;", }, { name: "MissingConns", - extraParams: "TOPUP_MONETARY_10;*topup;;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10", + extraParams: "TOPUP_MONETARY_10;*topup;;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10;", expectedErr: "MANDATORY_IE_MISSING: [connIDs]", }, { name: "WrongNumberOfParams", extraParams: "TOPUP_MONETARY_10;*topup;;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;10;;;", - expectedErr: "invalid number of parameters <20> expected 17", + expectedErr: "invalid number of parameters <20> expected 18", }, { name: "ActionIdEmptyFail", - extraParams: "DISABLE_ACC;;;;;;;;;;;;;;;;", + extraParams: "DISABLE_ACC;;;;;;;;;;;;;;;;;", expectedErr: `empty Action for dynamic_action`, }, { name: "ActionIdEmptyFail", - extraParams: ";;;;;;;;;;;;;;;;", + extraParams: ";;;;;;;;;;;;;;;;;", expectedErr: `empty ActionsId for dynamic_action`, }, { name: "WeightFail", - extraParams: "TOPUP_MONETARY_10;*topup;;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;BadString", + extraParams: "TOPUP_MONETARY_10;*topup;;*string:~*req.Account:1001&filter2;badID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;weekdays&offpeak;10;10;true;true;BadString;", expectedErr: `strconv.ParseFloat: parsing "BadString": invalid syntax`, }, } @@ -6376,12 +6376,12 @@ func TestDynamicFilter(t *testing.T) { { name: "ActivationIntervalBadStringFail", extraParams: "cgrates.org;Fltr_1;*string;~*req.Account;1001&1002;bad String;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "ActivationIntervalBadStringFail2", extraParams: "cgrates.org;Fltr_1;*string;~*req.Account;1001&1002;2014-07-29T15:00:00Z&bad String;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "InvalidOptsMap", @@ -6460,6 +6460,9 @@ func TestDynamicRoute(t *testing.T) { } return nil }, + utils.APIerSv1GetRouteProfile: func(ctx *context.Context, args2, reply any) error { + return nil + }, }, } connID := utils.ConcatenatedKey(utils.MetaInternal, utils.MetaApier) @@ -6542,7 +6545,7 @@ func TestDynamicRoute(t *testing.T) { "key": "value", }, }, - extraParams: "*tenant;RTP_ACNT_<~*req.Account>;*string:~*req.Account:<~*req.Account>&*string:~*req.Account:1002;*now&3000-07-29T15:00:00Z;*weight;*acd&*tcc;route1;*string:~*req.Account:<~*req.Account>&*string:~*req.Account:1002;<~*req.Account>&1002;RP1&RP2;RS1&RS2;Stat_1&Stat_1_1;10;true;param;10;key:value", + extraParams: "*tenant;route1@RTP_ACNT_1001;*string:~*req.Account:<~*req.Account>&*string:~*req.Account:1002;*now&3000-07-29T15:00:00Z;*weight;*acd&*tcc;route1;*string:~*req.Account:<~*req.Account>&*string:~*req.Account:1002;<~*req.Account>&1002;RP1&RP2;RS1&RS2;Stat_1&Stat_1_1;10;true;param;10;key:value", }, { name: "SuccessfulRequestEmptyFields", @@ -6552,7 +6555,7 @@ func TestDynamicRoute(t *testing.T) { Tenant: "cgrates.org", ID: "RTP_ACNT_1001", FilterIDs: nil, - ActivationInterval: &utils.ActivationInterval{}, + ActivationInterval: nil, SortingParameters: nil, Routes: []*Route{ { @@ -6584,6 +6587,11 @@ func TestDynamicRoute(t *testing.T) { extraParams: "tenant;RTP1;;", expectedErr: "invalid number of parameters <4> expected 17", }, + { + name: "RouteProfileIDFail", + extraParams: "cgrates.org;@@@;*string:~*req.Account:1001&*string:~*req.Account:1002;2014-07-29T15:00:00Z;*weight;*acd&*tcc;route1;*string:~*req.Account:1001&*string:~*req.Account:1002;1001&1002;RP1&RP2;RS1&RS2;Stat_1&Stat_1_1;10;true;param;10;key:value", + expectedErr: `more than 1 "@" character for RouteProfileID: <@@@>`, + }, { name: "ActivationIntervalLengthFail", extraParams: "cgrates.org;RTP_ACNT_1001;*string:~*req.Account:1001&*string:~*req.Account:1002;2014-07-29T15:00:00Z&&;*weight;*acd&*tcc;route1;*string:~*req.Account:1001&*string:~*req.Account:1002;1001&1002;RP1&RP2;RS1&RS2;Stat_1&Stat_1_1;10;true;param;10;key:value", @@ -6592,12 +6600,12 @@ func TestDynamicRoute(t *testing.T) { { name: "ActivationIntervalBadStringFail", extraParams: "cgrates.org;RTP_ACNT_1001;*string:~*req.Account:1001&*string:~*req.Account:1002;bad String;*weight;*acd&*tcc;route1;*string:~*req.Account:1001&*string:~*req.Account:1002;1001&1002;RP1&RP2;RS1&RS2;Stat_1&Stat_1_1;10;true;param;10;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "ActivationIntervalBadStringFail2", extraParams: "cgrates.org;RTP_ACNT_1001;*string:~*req.Account:1001&*string:~*req.Account:1002;2014-07-29T15:00:00Z&bad String;*weight;*acd&*tcc;route1;*string:~*req.Account:1001&*string:~*req.Account:1002;1001&1002;RP1&RP2;RS1&RS2;Stat_1&Stat_1_1;10;true;param;10;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "RouteWeightFail", @@ -7248,12 +7256,12 @@ func TestDynamicResource(t *testing.T) { { name: "ActivationIntervalBadStringFail", extraParams: "cgrates.org;RES_ACNT_1001;*string:~*req.Account:1001;bad String;1h;1;msg_1001;true;true;10;TD1&TD2;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "ActivationIntervalBadStringFail2", extraParams: "cgrates.org;RES_ACNT_1001;*string:~*req.Account:1001;2014-07-29T15:00:00Z&bad String;1h;1;msg_1001;true;true;10;TD1&TD2;key:value", - expectedErr: `parsing time "bad String" as "2006-01-02T15:04:05Z07:00": cannot parse "bad String" as "2006"`, + expectedErr: `Unsupported time format`, }, { name: "TTLFail", diff --git a/engine/libroutes.go b/engine/libroutes.go index a5e511429..4f6134a43 100644 --- a/engine/libroutes.go +++ b/engine/libroutes.go @@ -23,6 +23,7 @@ import ( "sort" "strings" + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" ) @@ -251,24 +252,31 @@ func (ssd RouteSortDispatcher) SortRoutes(prflID, strategy string, // SortedRoutesList represents the list of matched routes grouped based of profile type SortedRoutesList []*SortedRoutes -// RouteIDs returns a list of route IDs +// RouteIDs returns a list of route IDs. Attach RouteProfileID to the RouteIDs if RouteProfile is enabled in RouteSCfg func (sRs SortedRoutesList) RouteIDs() (rIDs []string) { for _, sR := range sRs { for _, r := range sR.Routes { - rIDs = append(rIDs, r.RouteID) + route := r.RouteID + if config.CgrConfig().AsteriskAgentCfg().RouteProfile { + route += "@" + sR.ProfileID + } + rIDs = append(rIDs, route) } } return } // RoutesWithParams returns a list of routes IDs with Parameters -func (sRs SortedRoutesList) RoutesWithParams() (sPs []string) { +func (sRs SortedRoutesList) RoutesWithParams(setRouteProfile bool) (sPs []string) { for _, sR := range sRs { for _, spl := range sR.Routes { route := spl.RouteID if spl.RouteParameters != "" { route += utils.InInFieldSep + spl.RouteParameters } + if setRouteProfile { + route += "@" + sR.ProfileID + } sPs = append(sPs, route) } } @@ -277,8 +285,8 @@ func (sRs SortedRoutesList) RoutesWithParams() (sPs []string) { // Digest returns list of routeIDs + parameters for easier outside access // format route1:route1params,route2:route2params -func (sRs SortedRoutesList) Digest() string { - return strings.Join(sRs.RoutesWithParams(), utils.FieldsSep) +func (sRs SortedRoutesList) Digest(setRouteProfile bool) string { + return strings.Join(sRs.RoutesWithParams(setRouteProfile), utils.FieldsSep) } // AsNavigableMap returns the SortedRoutesSet as NMInterface object diff --git a/engine/libroutes_test.go b/engine/libroutes_test.go index bdd4ae0b9..a1fc72417 100644 --- a/engine/libroutes_test.go +++ b/engine/libroutes_test.go @@ -1465,7 +1465,7 @@ func TestSortedRoutesListRoutesWithParams(t *testing.T) { }, }, } - val := sRs.RoutesWithParams() + val := sRs.RoutesWithParams(false) sort.Slice(val, func(i, j int) bool { return val[i] < val[j] }) @@ -1670,7 +1670,7 @@ func TestSortedRoutesListDigest(t *testing.T) { exp := "ROUTE_ID1:PARAM_1,ROUTE_ID2:PARAM_2,ROUTE_ID1:PARAM_1,ROUTE_ID2:PARAM_2" - if val := sRs.Digest(); val != exp { + if val := sRs.Digest(false); val != exp { t.Errorf("received %v", val) } } diff --git a/engine/routes.go b/engine/routes.go index 6cf9065d6..a84991e66 100644 --- a/engine/routes.go +++ b/engine/routes.go @@ -829,6 +829,6 @@ func (rpS *RouteService) V1GetRoutesList(ctx *context.Context, args *utils.CGREv if err = rpS.V1GetRoutes(ctx, args, sR); err != nil { return } - *reply = sR.RoutesWithParams() + *reply = sR.RoutesWithParams(false) return } diff --git a/engine/routes_test.go b/engine/routes_test.go index 2ae85ef3c..d7da62269 100644 --- a/engine/routes_test.go +++ b/engine/routes_test.go @@ -2637,7 +2637,31 @@ func TestSortedRoutesListDigestCase(t *testing.T) { }, } expectedDigest := "route1:param1,route2,route3:param3,route4" - result := srs.Digest() + result := srs.Digest(false) + if result != expectedDigest { + t.Errorf("Expected digest %s, but got %s", expectedDigest, result) + } +} + +func TestSortedRoutesListDigestCaseWithRouteProfile(t *testing.T) { + srs := SortedRoutesList{ + &SortedRoutes{ + ProfileID: "profile1", + Routes: []*SortedRoute{ + {RouteID: "route1", RouteParameters: "param1", SortingData: map[string]any{"key1": "value1"}, sortingDataF64: map[string]float64{utils.Weight: 1.0}}, + {RouteID: "route2", RouteParameters: "", SortingData: map[string]any{"key2": "value2"}, sortingDataF64: map[string]float64{utils.Weight: 2.0}}, + }, + }, + &SortedRoutes{ + ProfileID: "profile2", + Routes: []*SortedRoute{ + {RouteID: "route3", RouteParameters: "param3", SortingData: map[string]any{"key3": "value3"}, sortingDataF64: map[string]float64{utils.Weight: 3.0}}, + {RouteID: "route4", RouteParameters: "", SortingData: map[string]any{"key4": "value4"}, sortingDataF64: map[string]float64{utils.Weight: 4.0}}, + }, + }, + } + expectedDigest := "route1:param1@profile1,route2@profile1,route3:param3@profile2,route4@profile2" + result := srs.Digest(true) if result != expectedDigest { t.Errorf("Expected digest %s, but got %s", expectedDigest, result) } diff --git a/general_tests/dynamic_acc_route_modify_test.go b/general_tests/dynamic_acc_route_modify_test.go new file mode 100644 index 000000000..a424646bd --- /dev/null +++ b/general_tests/dynamic_acc_route_modify_test.go @@ -0,0 +1,371 @@ +//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 ( + "path" + "path/filepath" + "reflect" + "strconv" + "testing" + "time" + + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/sessions" + "github.com/cgrates/cgrates/utils" +) + +func TestDynamicAccountRouteModify(t *testing.T) { + switch *utils.DBType { + case utils.MetaInternal: + case utils.MetaMySQL, utils.MetaMongo, utils.MetaPostgres: + t.SkipNow() + default: + t.Fatal("unsupported dbtype value") + } + + ng := engine.TestEngine{ + ConfigPath: filepath.Join(*utils.DataDir, "conf", "samples", "dynamic_account_threshold"), + TpPath: path.Join(*utils.DataDir, "tariffplans", "testit"), + // LogBuffer: &bytes.Buffer{}, + } + // t.Cleanup(func() { fmt.Println(ng.LogBuffer) }) + client, _ := ng.Run(t) + + t.Run("SetInitiativeThresholdProfile", func(t *testing.T) { + time.Sleep(10 * time.Millisecond) // wait for tps to be loaded + thdPrf := &engine.ThresholdProfileWithAPIOpts{ + ThresholdProfile: &engine.ThresholdProfile{ + Tenant: "cgrates.org", + ID: "THD_DYNAMIC_STATS_AND_THRESHOLD_INIT", + FilterIDs: []string{"*string:~*req.Source:Terminate", + "*exists:~*req.Destination:", + "*lte:~*req.Usage:10s"}, + ActionIDs: []string{"ACT_DYN_THRESHOLD_AND_STATS_CREATION"}, + MinHits: 1, + MaxHits: -1, + Weight: 1, // keep in mind weight should be lower than the dynamicaly created thresholds so that we dont retrigger this threshold for the same Destination + Async: true, + }, + } + var reply string + if err := client.Call(context.Background(), utils.APIerSv1SetThresholdProfile, thdPrf, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned", reply) + } + }) + + rPrf := &engine.RouteWithAPIOpts{ + RouteProfile: &engine.RouteProfile{ + Tenant: "cgrates.org", + ID: "ROUTE_PROFILE_1", + Sorting: "*weight", + SortingParameters: []string{utils.MetaACD}, + Routes: []*engine.Route{ + { + ID: "Route1", + RatingPlanIDs: []string{"RPL1"}, + FilterIDs: []string{"*string:~*req.Destination:1002"}, + Weight: 10, + Blocker: false, + }, + { + ID: "Route2", + RatingPlanIDs: []string{"RPL2"}, + FilterIDs: []string{"*string:~*req.Destination:1003"}, + Weight: 20, + Blocker: false, + }, + }, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 29, 15, 0, 0, 0, time.UTC), + }, + Weight: 10, + }, + } + t.Run("SetStartingRouteProfile", func(t *testing.T) { + var reply string + if err := client.Call(context.Background(), utils.APIerSv1SetRouteProfile, rPrf, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned", reply) + } + }) + + t.Run("SetAfter3sTiming", func(t *testing.T) { + timing := &utils.TPTimingWithAPIOpts{ + TPTiming: &utils.TPTiming{ + ID: "TM_AFTER_3S", + StartTime: "+3s", // timing which will start the moment the action plan is executed. After the duration in StartTime, the Action from the actionPlan will be executed. Action plans executed this way will be triggered only once right when timer finishes + }, + } + var reply string + if err := client.Call(context.Background(), utils.APIerSv1SetTiming, timing, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned", reply) + } + }) + + t.Run("DynamicallyModifyRouteUsingActions", func(t *testing.T) { + attrs1 := &utils.AttrSetActions{ + ActionsId: "ACT_DYN_MODIFY_ROUTE", + Actions: []*utils.TPAction{ + { + Identifier: utils.MetaDynamicAction, + ExtraParameters: "ResetDynamicThreshold;*reset_threshold;\fcgrates.org:THD_DST_<~*req.Destination>_ROUTE_MODIFY\f;;;;;;;;;;;;;;10;true", + Weight: 15, // weight is important + }, + { + Identifier: utils.MetaDynamicActionPlan, + ExtraParameters: "ExecuteResetThreshold;ResetDynamicThreshold;TM_AFTER_3S;10;true", // reset threshold 3 seconds after THD_DST_<~*req.Destination>_ROUTE_MODIFY triggered so that we keep the threshold disabled for the 3 seconds + Weight: 10, // weight is important + }, + { + Identifier: utils.MetaDynamicRoute, + ExtraParameters: ";~*req.Route;;+3s;;;;;;;;;;;;;", + Weight: 5, // weight is important + }, + }, + } + var reply string + if err := client.Call(context.Background(), utils.APIerSv2SetActions, &attrs1, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned: %s", reply) + } + }) + + t.Run("SetDynamicThresholdAndStatsAction", func(t *testing.T) { + attrs1 := &utils.AttrSetActions{ + ActionsId: "ACT_DYN_THRESHOLD_AND_STATS_CREATION", + Actions: []*utils.TPAction{ + { + Identifier: utils.MetaDynamicThreshold, + ExtraParameters: "*tenant;THD_BLOCKER_DST_<~*req.Destination>;*string:~*req.Destination:<~*req.Destination>;*now;-1;1;;true;3;;true;;", + }, + { + Identifier: utils.MetaDynamicThreshold, + ExtraParameters: "*tenant;THD_DST_<~*req.Destination>_ROUTE_MODIFY;*string:~*req.Source:Terminate&*string:~*req.Destination:<~*req.Destination>&*lte:~*req.Usage:10s;*now;-1;5;3s;true;4;ACT_DYN_MODIFY_ROUTE;true;;", + }, + }, + } + var reply string + if err := client.Call(context.Background(), utils.APIerSv2SetActions, &attrs1, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned: %s", reply) + } + }) + + t.Run("SetActionPlanOfDynaPrepaidAccounts", func(t *testing.T) { + var reply string + atms1 := &engine.AttrSetActionPlan{ + Id: "DYNA_ACC", + ActionPlan: []*engine.AttrActionPlan{ + { + ActionsId: "TOPUP_RST_MONETARY_10", + Time: utils.MetaMonthlyEstimated, + TimingID: utils.MetaMonthlyEstimated, + Weight: 20, + }, + }, + Overwrite: false, + } + if err := client.Call(context.Background(), utils.APIerSv1SetActionPlan, &atms1, &reply); err != nil { + t.Error("Got error on APIerSv1.SetActionPlan: ", err.Error()) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned: %s", reply) + } + }) + + t.Run("Make5TerminateCalls", func(t *testing.T) { + args1 := &sessions.V1TerminateSessionArgs{ + TerminateSession: true, + ProcessThresholds: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{ + utils.ACD: 7 * time.Second, + utils.AccountField: "CreatedAccount", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.Category: "call", + utils.Cost: -1, + utils.Destination: "1002", + utils.OriginID: "sessDynaprepaid", + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.MetaDynaprepaid, + utils.Route: "Route1@ROUTE_PROFILE_1", + utils.Source: "Terminate", + utils.Tenant: "cgrates.org", + utils.ToR: utils.MetaVoice, + utils.Usage: 7 * time.Second, + }, + }, + } + var rply1 string + if err := client.Call(context.Background(), utils.SessionSv1TerminateSession, + args1, &rply1); err != nil { + t.Error(err) + return + } else if rply1 != utils.OK { + t.Errorf("Unexpected reply: %s", rply1) + } + for i := range 5 { + strI := strconv.Itoa(i) + args1 := &sessions.V1TerminateSessionArgs{ + TerminateSession: true, + ProcessThresholds: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{ + utils.ACD: 7 * time.Second, + utils.AccountField: "CreatedAccount", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.Category: "call", + utils.Cost: -1, + utils.Destination: "1002", + utils.OriginID: "sessPrepaid" + strI, + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.MetaDynaprepaid, + utils.Route: "Route1@ROUTE_PROFILE_1", + utils.Source: "Terminate", + utils.Tenant: "cgrates.org", + utils.ToR: utils.MetaVoice, + utils.Usage: 7 * time.Second, + }, + }, + } + var rply1 string + if err := client.Call(context.Background(), utils.SessionSv1TerminateSession, + args1, &rply1); err != nil { + t.Error(err) + return + } else if rply1 != utils.OK { + t.Errorf("Unexpected reply: %s", rply1) + } + } + }) + + t.Run("CheckModifiedRoute", func(t *testing.T) { + // wait for route to be modified async + time.Sleep(10 * time.Millisecond) + routeProfileFound := new(engine.RouteProfile) + if err := client.Call(context.Background(), utils.APIerSv1GetRouteProfile, + &utils.TenantID{Tenant: "cgrates.org", ID: "ROUTE_PROFILE_1"}, &routeProfileFound); err != nil { + t.Error(err) + } + if routeProfileFound.ActivationInterval.ActivationTime.Equal(time.Date(2014, 7, 29, 15, 0, 0, 0, time.UTC)) { + t.Fatalf("Activation time didnt change, received <%v>", routeProfileFound.ActivationInterval.ActivationTime) + } + rPrf.ActivationInterval = routeProfileFound.ActivationInterval + if !reflect.DeepEqual(utils.ToJSON(rPrf.RouteProfile), utils.ToJSON(routeProfileFound)) { + t.Errorf("Expected <%v>, \nreceived <%v>", utils.ToJSON(rPrf.RouteProfile), utils.ToJSON(routeProfileFound)) + } + }) + t.Run("Make5TerminateCalls2", func(t *testing.T) { + time.Sleep(4 * time.Second) // wait for threshold to be reset + args1 := &sessions.V1TerminateSessionArgs{ + TerminateSession: true, + ProcessThresholds: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{ + utils.ACD: 7 * time.Second, + utils.AccountField: "CreatedAccount", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.Category: "call", + utils.Cost: -1, + utils.Destination: "1002", + utils.OriginID: "sessDynaprepaid", + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.MetaDynaprepaid, + utils.Route: "Route1@ROUTE_PROFILE_1", + utils.Source: "Terminate", + utils.Tenant: "cgrates.org", + utils.ToR: utils.MetaVoice, + utils.Usage: 7 * time.Second, + }, + }, + } + var rply1 string + if err := client.Call(context.Background(), utils.SessionSv1TerminateSession, + args1, &rply1); err != nil { + t.Error(err) + return + } else if rply1 != utils.OK { + t.Errorf("Unexpected reply: %s", rply1) + } + for i := range 5 { + strI := strconv.Itoa(i + 5) + args1 := &sessions.V1TerminateSessionArgs{ + TerminateSession: true, + ProcessThresholds: true, + CGREvent: &utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]any{ + utils.ACD: 7 * time.Second, + utils.AccountField: "CreatedAccount", + utils.AnswerTime: time.Date(2018, 8, 24, 16, 00, 26, 0, time.UTC), + utils.Category: "call", + utils.Cost: -1, + utils.Destination: "1002", + utils.OriginID: "sessPrepaid" + strI, + utils.OriginHost: "192.168.1.1", + utils.RequestType: utils.MetaDynaprepaid, + utils.Route: "Route1@ROUTE_PROFILE_1", + utils.Source: "Terminate", + utils.Tenant: "cgrates.org", + utils.ToR: utils.MetaVoice, + utils.Usage: 7 * time.Second, + }, + }, + } + var rply1 string + if err := client.Call(context.Background(), utils.SessionSv1TerminateSession, + args1, &rply1); err != nil { + t.Error(err) + return + } else if rply1 != utils.OK { + t.Errorf("Unexpected reply: %s", rply1) + } + } + }) + + t.Run("CheckModifiedRoute2", func(t *testing.T) { + // wait for route to be modified async + time.Sleep(10 * time.Millisecond) + routeProfileFound := new(engine.RouteProfile) + if err := client.Call(context.Background(), utils.APIerSv1GetRouteProfile, + &utils.TenantID{Tenant: "cgrates.org", ID: "ROUTE_PROFILE_1"}, &routeProfileFound); err != nil { + t.Error(err) + } + if routeProfileFound.ActivationInterval.ActivationTime.Equal(rPrf.ActivationInterval.ActivationTime) { + t.Fatalf("Activation time didnt change, received <%v>", routeProfileFound.ActivationInterval.ActivationTime) + } + rPrf.ActivationInterval = routeProfileFound.ActivationInterval + if !reflect.DeepEqual(utils.ToJSON(rPrf.RouteProfile), utils.ToJSON(routeProfileFound)) { + t.Errorf("Expected <%v>, \nreceived <%v>", utils.ToJSON(rPrf.RouteProfile), utils.ToJSON(routeProfileFound)) + } + }) +} diff --git a/general_tests/dynamic_thresholds_it_test.go b/general_tests/dynamic_thresholds_it_test.go index 194362127..a17fd8382 100644 --- a/general_tests/dynamic_thresholds_it_test.go +++ b/general_tests/dynamic_thresholds_it_test.go @@ -289,7 +289,7 @@ func testDynThdSetAction(t *testing.T) { }, { Identifier: utils.MetaDynamicAction, - ExtraParameters: "DYNAMICLY_ACT_<~*req.ID>;*cdrlog;\f{\"Account\":\"<~*req.ID>\",\"RequestType\":\"*pseudoprepaid\",\"Subject\":\"DifferentThanAccount\", \"ToR\":\"~ActionType:s/^\\*(.*)$/did_$1/\"}\f;*string:~*req.Account:<~*req.ID>&filter2;balID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;*daily;10;10;true;false;10", + ExtraParameters: "DYNAMICLY_ACT_<~*req.ID>;*cdrlog;\f{\"Account\":\"<~*req.ID>\",\"RequestType\":\"*pseudoprepaid\",\"Subject\":\"DifferentThanAccount\", \"ToR\":\"~ActionType:s/^\\*(.*)$/did_$1/\"}\f;*string:~*req.Account:<~*req.ID>&filter2;balID;*monetary;call&data;1002&1003;SPECIAL_1002;SHARED_A&SHARED_B;*unlimited;*daily;10;10;true;false;10;false", }, { Identifier: utils.MetaDynamicDestination, diff --git a/services/freeswitchagent_it_test.go b/services/freeswitchagent_it_test.go index f347bfb0a..a935e66b5 100644 --- a/services/freeswitchagent_it_test.go +++ b/services/freeswitchagent_it_test.go @@ -206,6 +206,7 @@ func TestFreeSwitchAgentReload4(t *testing.T) { SessionSConns: nil, SubscribePark: true, CreateCDR: true, + RouteProfile: true, ExtraFields: nil, LowBalanceAnnFile: "", EmptyBalanceContext: "", @@ -294,6 +295,7 @@ func TestFreeSwitchAgentReload6(t *testing.T) { SessionSConns: nil, SubscribePark: true, CreateCDR: true, + RouteProfile: true, ExtraFields: nil, LowBalanceAnnFile: "", EmptyBalanceContext: "", diff --git a/services/kamailioagent_it_test.go b/services/kamailioagent_it_test.go index 1ca12fd0d..639ae5b9d 100644 --- a/services/kamailioagent_it_test.go +++ b/services/kamailioagent_it_test.go @@ -102,6 +102,7 @@ func TestKamailioAgentReload(t *testing.T) { Enabled: true, SessionSConns: []string{utils.ConcatenatedKey("*birpc_internal", utils.MetaSessionS)}, CreateCdr: true, + RouteProfile: false, EvapiConns: []*config.KamConnCfg{{Address: "127.0.0.1:8448", Reconnects: 10, Alias: "randomAlias"}}, Timezone: "Local", } diff --git a/sessions/sessions.go b/sessions/sessions.go index 85ae164d2..bcc6f2e75 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -2271,7 +2271,7 @@ func (sS *SessionS) BiRPCv1AuthorizeEventWithDigest(ctx *context.Context, authReply.MaxUsage = initAuthRply.MaxUsage.Seconds() } if args.GetRoutes { - authReply.RoutesDigest = utils.StringPointer(initAuthRply.RouteProfiles.Digest()) + authReply.RoutesDigest = utils.StringPointer(initAuthRply.RouteProfiles.Digest(false)) } if args.ProcessThresholds { authReply.Thresholds = utils.StringPointer( diff --git a/utils/consts.go b/utils/consts.go index 51492ad85..0de1c442a 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -2539,9 +2539,10 @@ const ( AdminPasswordCfg = "admin_password" // KamAgentCfg - EvapiConnsCfg = "evapi_conns" - TimezoneCfg = "timezone" - TimezoneCfgC = "Timezone" + EvapiConnsCfg = "evapi_conns" + TimezoneCfg = "timezone" + TimezoneCfgC = "Timezone" + RouteProfileCfg = "route_profile" // AsteriskConnCfg UserCf = "user"