diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 0391dea1e..e28ca107d 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -97,7 +97,9 @@ func startCdrcs(internalCdrSChan, internalRaterChan chan rpcclient.RpcClientConn } if len(enabledCfgs) != 0 { - go startCdrc(internalCdrSChan, internalRaterChan, cdrcCfgs, cfg.HttpSkipTlsVerify, cdrcChildrenChan, exitChan) + go startCdrc(internalCdrSChan, internalRaterChan, enabledCfgs, cfg.HttpSkipTlsVerify, cdrcChildrenChan, exitChan) + } else { + utils.Logger.Info(" No enabled CDRC clients") } } cdrcInitialized = true // Initialized diff --git a/config/cdrcconfig.go b/config/cdrcconfig.go index c632bdf13..fd9f09735 100644 --- a/config/cdrcconfig.go +++ b/config/cdrcconfig.go @@ -162,6 +162,10 @@ func (self *CdrcConfig) Clone() *CdrcConfig { clnCdrc.MaxOpenFiles = self.MaxOpenFiles clnCdrc.CdrInDir = self.CdrInDir clnCdrc.CdrOutDir = self.CdrOutDir + clnCdrc.CDRPath = make(utils.HierarchyPath, len(self.CDRPath)) + for i, path := range self.CDRPath { + clnCdrc.CDRPath[i] = path + } clnCdrc.CdrSourceId = self.CdrSourceId clnCdrc.PartialRecordCache = self.PartialRecordCache clnCdrc.PartialCacheExpiryAction = self.PartialCacheExpiryAction diff --git a/config/config.go b/config/config.go index 5d4dc0cbc..5ca842aee 100644 --- a/config/config.go +++ b/config/config.go @@ -909,19 +909,44 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error { self.CdrcProfiles = make(map[string][]*CdrcConfig) } for _, jsnCrc1Cfg := range jsnCdrcCfg { - if _, hasDir := self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir]; !hasDir { - self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir] = make([]*CdrcConfig, 0) + if jsnCrc1Cfg.Id == nil || *jsnCrc1Cfg.Id == "" { + return errors.New("CDRC profile without an id") } + if *jsnCrc1Cfg.Id == utils.META_DEFAULT { + if self.dfltCdrcProfile == nil { + self.dfltCdrcProfile = new(CdrcConfig) + } + } + indxFound := -1 // Will be different than -1 if an instance with same id will be found + pathFound := "" // Will be populated with the path where slice of cfgs was found var cdrcInstCfg *CdrcConfig - if *jsnCrc1Cfg.Id == utils.META_DEFAULT && self.dfltCdrcProfile == nil { - cdrcInstCfg = new(CdrcConfig) - } else { - cdrcInstCfg = self.dfltCdrcProfile.Clone() // Clone default so we do not inherit pointers + for path := range self.CdrcProfiles { + for i := range self.CdrcProfiles[path] { + if self.CdrcProfiles[path][i].ID == *jsnCrc1Cfg.Id { + indxFound = i + pathFound = path + cdrcInstCfg = self.CdrcProfiles[path][i] + break + } + } + } + if cdrcInstCfg == nil { + cdrcInstCfg = self.dfltCdrcProfile.Clone() } if err := cdrcInstCfg.loadFromJsonCfg(jsnCrc1Cfg); err != nil { return err } - self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir] = append(self.CdrcProfiles[*jsnCrc1Cfg.Cdr_in_dir], cdrcInstCfg) + if cdrcInstCfg.CdrInDir == "" { + return errors.New("CDRC profile without cdr_in_dir") + } + if _, hasDir := self.CdrcProfiles[cdrcInstCfg.CdrInDir]; !hasDir { + self.CdrcProfiles[cdrcInstCfg.CdrInDir] = make([]*CdrcConfig, 0) + } + if indxFound != -1 { // Replace previous config so we have inheritance + self.CdrcProfiles[pathFound][indxFound] = cdrcInstCfg + } else { + self.CdrcProfiles[cdrcInstCfg.CdrInDir] = append(self.CdrcProfiles[cdrcInstCfg.CdrInDir], cdrcInstCfg) + } } } if jsnSmGenericCfg != nil { diff --git a/config/config_test.go b/config/config_test.go index 204aaa8b9..8327407af 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -21,6 +21,9 @@ package config import ( "reflect" "testing" + "time" + + "github.com/cgrates/cgrates/utils" ) var cfg *CGRConfig @@ -58,3 +61,72 @@ func TestLoadCgrCfgWithDefaults(t *testing.T) { t.Errorf("Expected: %+v, received: %+v", eCgrCfg.SmFsConfig, cgrCfg.SmFsConfig) } } + +func TestCgrCfgCDRC(t *testing.T) { + JSN_RAW_CFG := ` +{ +"cdrc": [ + { + "id": "*default", + "enabled": true, // enable CDR client functionality + "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value + {"field_id": "ToR", "type": "*composed", "value": "~7:s/^(voice|data|sms|mms|generic)$/*$1/"}, + {"field_id": "AnswerTime", "type": "*composed", "value": "1"}, + {"field_id": "Usage", "type": "*composed", "value": "~9:s/^(\\d+)$/${1}s/"}, + ], + }, +], +}` + eCgrCfg, _ := NewDefaultCGRConfig() + eCgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"] = []*CdrcConfig{ + &CdrcConfig{ + ID: utils.META_DEFAULT, + Enabled: true, + DryRun: false, + CdrsConns: []*HaPoolConfig{&HaPoolConfig{Address: utils.MetaInternal}}, + CdrFormat: "csv", + FieldSeparator: rune(','), + DataUsageMultiplyFactor: 1024, + Timezone: "", + RunDelay: 0, + MaxOpenFiles: 1024, + CdrInDir: "/var/spool/cgrates/cdrc/in", + CdrOutDir: "/var/spool/cgrates/cdrc/out", + FailedCallsPrefix: "missed_calls", + CDRPath: utils.HierarchyPath([]string{""}), + CdrSourceId: "freeswitch_csv", + ContinueOnSuccess: false, + PartialRecordCache: time.Duration(10 * time.Second), + PartialCacheExpiryAction: "*dump_to_file", + HeaderFields: make([]*CfgCdrField, 0), + ContentFields: []*CfgCdrField{ + &CfgCdrField{FieldId: "ToR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("~7:s/^(voice|data|sms|mms|generic)$/*$1/", utils.INFIELD_SEP)}, + &CfgCdrField{FieldId: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("1", utils.INFIELD_SEP)}, + &CfgCdrField{FieldId: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile("~9:s/^(\\d+)$/${1}s/", utils.INFIELD_SEP)}, + }, + TrailerFields: make([]*CfgCdrField, 0), + CacheDumpFields: []*CfgCdrField{ + &CfgCdrField{Tag: "CGRID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CGRID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RunID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.MEDI_RUNID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "TOR", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TOR, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "OriginID", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCID, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "RequestType", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.REQTYPE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Direction", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DIRECTION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Tenant", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.TENANT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Category", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.CATEGORY, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Account", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ACCOUNT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Subject", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SUBJECT, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Destination", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.DESTINATION, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "SetupTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.SETUP_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "AnswerTime", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.ANSWER_TIME, utils.INFIELD_SEP), Layout: "2006-01-02T15:04:05Z07:00"}, + &CfgCdrField{Tag: "Usage", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.USAGE, utils.INFIELD_SEP)}, + &CfgCdrField{Tag: "Cost", Type: utils.META_COMPOSED, Value: utils.ParseRSRFieldsMustCompile(utils.COST, utils.INFIELD_SEP)}, + }, + }, + } + if cgrCfg, err := NewCGRConfigFromJsonStringWithDefaults(JSN_RAW_CFG); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eCgrCfg.CdrcProfiles, cgrCfg.CdrcProfiles) { + t.Errorf("Expected: %+v, received: %+v", eCgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0], cgrCfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0]) + } +} diff --git a/config/configcdrc_test.go b/config/configcdrc_test.go index 0fb0097df..c7d45c6f1 100644 --- a/config/configcdrc_test.go +++ b/config/configcdrc_test.go @@ -111,7 +111,7 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { MaxOpenFiles: 1024, CdrInDir: "/tmp/cgrates/cdrc1/in", CdrOutDir: "/tmp/cgrates/cdrc1/out", - CDRPath: nil, + CDRPath: utils.HierarchyPath([]string{""}), CdrSourceId: "csv1", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), PartialRecordCache: time.Duration(10) * time.Second, @@ -175,7 +175,7 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { MaxOpenFiles: 1024, CdrInDir: "/tmp/cgrates/cdrc2/in", CdrOutDir: "/tmp/cgrates/cdrc2/out", - CDRPath: nil, + CDRPath: utils.HierarchyPath([]string{""}), CdrSourceId: "csv2", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), PartialRecordCache: time.Duration(10) * time.Second, @@ -221,7 +221,7 @@ func TestLoadCdrcConfigMultipleFiles(t *testing.T) { MaxOpenFiles: 1024, CdrInDir: "/tmp/cgrates/cdrc3/in", CdrOutDir: "/tmp/cgrates/cdrc3/out", - CDRPath: nil, + CDRPath: utils.HierarchyPath([]string{""}), CdrSourceId: "csv3", CdrFilter: utils.ParseRSRFieldsMustCompile("", utils.INFIELD_SEP), PartialRecordCache: time.Duration(10) * time.Second, diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index f3abf0489..8ce018399 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -130,7 +130,7 @@ CREATE TABLE `tp_shared_groups` ( `id` int(11) NOT NULL AUTO_INCREMENT, `tpid` varchar(64) NOT NULL, `tag` varchar(64) NOT NULL, - `account` varchar(24) NOT NULL, + `account` varchar(64) NOT NULL, `strategy` varchar(24) NOT NULL, `rating_subject` varchar(24) NOT NULL, `created_at` TIMESTAMP, @@ -258,7 +258,7 @@ CREATE TABLE tp_lcr_rules ( `direction` varchar(8) NOT NULL, `tenant` varchar(64) NOT NULL, `category` varchar(32) NOT NULL, - `account` varchar(24) NOT NULL, + `account` varchar(64) NOT NULL, `subject` varchar(64) NOT NULL, `destination_tag` varchar(64) NOT NULL, `rp_category` varchar(32) NOT NULL, @@ -283,7 +283,7 @@ CREATE TABLE tp_derived_chargers ( `direction` varchar(8) NOT NULL, `tenant` varchar(64) NOT NULL, `category` varchar(32) NOT NULL, - `account` varchar(24) NOT NULL, + `account` varchar(64) NOT NULL, `subject` varchar(64) NOT NULL, `destination_ids` varchar(64) NOT NULL, `runid` varchar(24) NOT NULL, @@ -292,8 +292,8 @@ CREATE TABLE tp_derived_chargers ( `direction_field` varchar(24) NOT NULL, `tenant_field` varchar(24) NOT NULL, `category_field` varchar(24) NOT NULL, - `account_field` varchar(24) NOT NULL, - `subject_field` varchar(24) NOT NULL, + `account_field` varchar(64) NOT NULL, + `subject_field` varchar(64) NOT NULL, `destination_field` varchar(24) NOT NULL, `setup_time_field` varchar(24) NOT NULL, `pdd_field` varchar(24) NOT NULL, @@ -330,7 +330,7 @@ CREATE TABLE tp_cdr_stats ( `directions` varchar(8) NOT NULL, `tenants` varchar(64) NOT NULL, `categories` varchar(32) NOT NULL, - `accounts` varchar(24) NOT NULL, + `accounts` varchar(255) NOT NULL, `subjects` varchar(64) NOT NULL, `destination_ids` varchar(64) NOT NULL, `pdd_interval` varchar(64) NOT NULL, @@ -338,7 +338,7 @@ CREATE TABLE tp_cdr_stats ( `suppliers` varchar(64) NOT NULL, `disconnect_causes` varchar(64) NOT NULL, `mediation_runids` varchar(64) NOT NULL, - `rated_accounts` varchar(64) NOT NULL, + `rated_accounts` varchar(255) NOT NULL, `rated_subjects` varchar(64) NOT NULL, `cost_interval` varchar(24) NOT NULL, `action_triggers` varchar(64) NOT NULL, @@ -408,6 +408,6 @@ CREATE TABLE tp_resource_limits ( PRIMARY KEY (`id`), KEY `tpid` (`tpid`), UNIQUE KEY `unique_tp_resource_limits` (`tpid`, `tag`) -); +); diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index cbb62ba70..bb633d863 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -125,7 +125,7 @@ CREATE TABLE tp_shared_groups ( id SERIAL PRIMARY KEY, tpid VARCHAR(64) NOT NULL, tag VARCHAR(64) NOT NULL, - account VARCHAR(24) NOT NULL, + account VARCHAR(64) NOT NULL, strategy VARCHAR(24) NOT NULL, rating_subject VARCHAR(24) NOT NULL, created_at TIMESTAMP, @@ -253,7 +253,7 @@ CREATE TABLE tp_lcr_rules ( direction VARCHAR(8) NOT NULL, tenant VARCHAR(64) NOT NULL, category VARCHAR(32) NOT NULL, - account VARCHAR(24) NOT NULL, + account VARCHAR(64) NOT NULL, subject VARCHAR(64) NOT NULL, destination_tag VARCHAR(64) NOT NULL, rp_category VARCHAR(32) NOT NULL, @@ -278,7 +278,7 @@ CREATE TABLE tp_derived_chargers ( direction VARCHAR(8) NOT NULL, tenant VARCHAR(64) NOT NULL, category VARCHAR(32) NOT NULL, - account VARCHAR(24) NOT NULL, + account VARCHAR(64) NOT NULL, subject VARCHAR(64) NOT NULL, destination_ids VARCHAR(64) NOT NULL, runid VARCHAR(24) NOT NULL, @@ -287,8 +287,8 @@ CREATE TABLE tp_derived_chargers ( direction_field VARCHAR(24) NOT NULL, tenant_field VARCHAR(24) NOT NULL, category_field VARCHAR(24) NOT NULL, - account_field VARCHAR(24) NOT NULL, - subject_field VARCHAR(24) NOT NULL, + account_field VARCHAR(64) NOT NULL, + subject_field VARCHAR(64) NOT NULL, destination_field VARCHAR(24) NOT NULL, setup_time_field VARCHAR(24) NOT NULL, pdd_field VARCHAR(24) NOT NULL, @@ -325,7 +325,7 @@ CREATE TABLE tp_cdr_stats ( directions VARCHAR(8) NOT NULL, tenants VARCHAR(64) NOT NULL, categories VARCHAR(32) NOT NULL, - accounts VARCHAR(24) NOT NULL, + accounts VARCHAR(255) NOT NULL, subjects VARCHAR(64) NOT NULL, destination_ids VARCHAR(64) NOT NULL, pdd_interval VARCHAR(64) NOT NULL, @@ -333,7 +333,7 @@ CREATE TABLE tp_cdr_stats ( suppliers VARCHAR(64) NOT NULL, disconnect_causes VARCHAR(64) NOT NULL, mediation_runids VARCHAR(64) NOT NULL, - rated_accounts VARCHAR(64) NOT NULL, + rated_accounts VARCHAR(255) NOT NULL, rated_subjects VARCHAR(64) NOT NULL, cost_interval VARCHAR(24) NOT NULL, action_triggers VARCHAR(64) NOT NULL, @@ -402,4 +402,4 @@ CREATE TABLE tp_resource_limits ( ); CREATE INDEX tp_resource_limits_idx ON tp_resource_limits (tpid); CREATE INDEX tp_resource_limits_unique ON tp_resource_limits ("tpid", "tag"); - + diff --git a/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg b/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg index 5bfac3ee6..9173b318e 100644 --- a/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg +++ b/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg @@ -140,7 +140,7 @@ route[CGR_AUTH_REQ] { $json(cgr_auth/id) = "1"; $json(cgr_auth/method) = "ApierV1.GetMaxUsage"; $json(cgr_auth/params) := "[{}]"; - $json(cgr_auth/params[0]/ReqType) = $avp(cgr_reqtype); + $json(cgr_auth/params[0]/RequestType) = $avp(cgr_reqtype); $json(cgr_auth/params[0]/Account) = $avp(cgr_account); $json(cgr_auth/params[0]/Destination) = $avp(cgr_destination); $json(cgr_auth/params[0]/DialogId) = $DLG_did; diff --git a/engine/reslimiter.go b/engine/reslimiter.go index be5c5505e..e040a9f46 100644 --- a/engine/reslimiter.go +++ b/engine/reslimiter.go @@ -302,7 +302,7 @@ func (rls *ResourceLimiterService) V1ResourceLimitsForEvent(ev map[string]interf return nil } -// Alias API for external usage +// Alias API for external use func (rls *ResourceLimiterService) ResourceLimitsForEvent(ev map[string]interface{}, reply *[]*ResourceLimit) error { return rls.V1ResourceLimitsForEvent(ev, reply) }