diff --git a/apier/cdre.go b/apier/cdre.go index 0a76d15bd..5652d8e14 100644 --- a/apier/cdre.go +++ b/apier/cdre.go @@ -130,10 +130,8 @@ func (self *ApierV1) ExportCdrsToFile(attr utils.AttrExpFileCdrs, reply *utils.E } exportTemplate := self.Config.CdreFWXmlTemplate if len(attr.ExportTemplate) != 0 && self.Config.XmlCfgDocument != nil { - if xmlTemplate, err := self.Config.XmlCfgDocument.GetCdreFWCfg(attr.ExportTemplate[len(utils.XML_PROFILE_PREFIX):]); err != nil { - return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) - } else if xmlTemplate != nil { - exportTemplate = xmlTemplate + if xmlTemplate := self.Config.XmlCfgDocument.GetCdreFWCfgs(attr.ExportTemplate[len(utils.XML_PROFILE_PREFIX):]); xmlTemplate != nil { + exportTemplate = xmlTemplate[attr.ExportTemplate[len(utils.XML_PROFILE_PREFIX):]] } } if exportTemplate == nil { diff --git a/cdrc/cdrc.go b/cdrc/cdrc.go index daa41dd26..ef4027345 100644 --- a/cdrc/cdrc.go +++ b/cdrc/cdrc.go @@ -31,7 +31,6 @@ import ( "time" "github.com/cgrates/cgrates/cdrs" - "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/utils" "github.com/howeyc/fsnotify" @@ -42,12 +41,13 @@ const ( FS_CSV = "freeswitch_csv" ) -func NewCdrc(config *config.CGRConfig, cdrServer *cdrs.CDRS) (*Cdrc, error) { - cdrc := &Cdrc{cgrCfg: config, cdrServer: cdrServer} +func NewCdrc(cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId string, runDelay time.Duration, cdrFields map[string]*utils.RSRField, cdrServer *cdrs.CDRS) (*Cdrc, error) { + cdrc := &Cdrc{cdrsAddress: cdrsAddress, cdrType: cdrType, cdrInDir: cdrInDir, cdrOutDir: cdrOutDir, + cdrSourceId: cdrSourceId, runDelay: runDelay, cdrFields: cdrFields, cdrServer: cdrServer} // Before processing, make sure in and out folders exist - for _, dir := range []string{cdrc.cgrCfg.CdrcCdrInDir, cdrc.cgrCfg.CdrcCdrOutDir} { + for _, dir := range []string{cdrc.cdrInDir, cdrc.cdrOutDir} { if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) { - return nil, fmt.Errorf("Folder %s does not exist", dir) + return nil, fmt.Errorf("Inexistent folder: %s", dir) } } cdrc.httpClient = new(http.Client) @@ -55,31 +55,36 @@ func NewCdrc(config *config.CGRConfig, cdrServer *cdrs.CDRS) (*Cdrc, error) { } type Cdrc struct { - cgrCfg *config.CGRConfig - cdrServer *cdrs.CDRS - cfgCdrFields map[string]string // Key is the name of the field - httpClient *http.Client + cdrsAddress, + cdrType, + cdrInDir, + cdrOutDir, + cdrSourceId string + runDelay time.Duration + cdrFields map[string]*utils.RSRField + cdrServer *cdrs.CDRS // Reference towards internal cdrServer if that is the case + httpClient *http.Client } // When called fires up folder monitoring, either automated via inotify or manual by sleeping between processing func (self *Cdrc) Run() error { - if self.cgrCfg.CdrcRunDelay == time.Duration(0) { // Automated via inotify + if self.runDelay == time.Duration(0) { // Automated via inotify return self.trackCDRFiles() } // No automated, process and sleep approach for { self.processCdrDir() - time.Sleep(self.cgrCfg.CdrcRunDelay) + time.Sleep(self.runDelay) } } // Takes the record out of csv and turns it into http form which can be posted func (self *Cdrc) recordForkCdr(record []string) (*utils.StoredCdr, error) { - storedCdr := &utils.StoredCdr{TOR: utils.VOICE, CdrSource: self.cgrCfg.CdrcSourceId, ExtraFields: make(map[string]string), Cost: -1} + storedCdr := &utils.StoredCdr{TOR: utils.VOICE, CdrSource: self.cdrSourceId, ExtraFields: make(map[string]string), Cost: -1} var err error - for cfgFieldName, cfgFieldRSR := range self.cgrCfg.CdrcCdrFields { + for cfgFieldName, cfgFieldRSR := range self.cdrFields { var fieldVal string - if utils.IsSliceMember([]string{CSV, FS_CSV}, self.cgrCfg.CdrcCdrType) { + if utils.IsSliceMember([]string{CSV, FS_CSV}, self.cdrType) { if cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id); len(record) <= cfgFieldIdx { return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s", record, cfgFieldName) } else { @@ -128,11 +133,11 @@ func (self *Cdrc) recordForkCdr(record []string) (*utils.StoredCdr, error) { // One run over the CDR folder func (self *Cdrc) processCdrDir() error { - engine.Logger.Info(fmt.Sprintf(" Parsing folder %s for CDR files.", self.cgrCfg.CdrcCdrInDir)) - filesInDir, _ := ioutil.ReadDir(self.cgrCfg.CdrcCdrInDir) + engine.Logger.Info(fmt.Sprintf(" Parsing folder %s for CDR files.", self.cdrInDir)) + filesInDir, _ := ioutil.ReadDir(self.cdrInDir) for _, file := range filesInDir { - if self.cgrCfg.CdrcCdrType != FS_CSV || path.Ext(file.Name()) != ".csv" { - if err := self.processFile(path.Join(self.cgrCfg.CdrcCdrInDir, file.Name())); err != nil { + if self.cdrType != FS_CSV || path.Ext(file.Name()) != ".csv" { + if err := self.processFile(path.Join(self.cdrInDir, file.Name())); err != nil { return err } } @@ -147,15 +152,15 @@ func (self *Cdrc) trackCDRFiles() (err error) { return } defer watcher.Close() - err = watcher.Watch(self.cgrCfg.CdrcCdrInDir) + err = watcher.Watch(self.cdrInDir) if err != nil { return } - engine.Logger.Info(fmt.Sprintf(" Monitoring %s for file moves.", self.cgrCfg.CdrcCdrInDir)) + engine.Logger.Info(fmt.Sprintf(" Monitoring %s for file moves.", self.cdrInDir)) for { select { case ev := <-watcher.Event: - if ev.IsCreate() && (self.cgrCfg.CdrcCdrType != FS_CSV || path.Ext(ev.Name) != ".csv") { + if ev.IsCreate() && (self.cdrType != FS_CSV || path.Ext(ev.Name) != ".csv") { if err = self.processFile(ev.Name); err != nil { engine.Logger.Err(fmt.Sprintf("Processing file %s, error: %s", ev.Name, err.Error())) } @@ -190,20 +195,20 @@ func (self *Cdrc) processFile(filePath string) error { engine.Logger.Err(fmt.Sprintf(" Error in csv file: %s", err.Error())) continue } - if self.cgrCfg.CdrcCdrs == utils.INTERNAL { + if self.cdrsAddress == utils.INTERNAL { if err := self.cdrServer.ProcessRawCdr(storedCdr); err != nil { engine.Logger.Err(fmt.Sprintf(" Failed posting CDR, error: %s", err.Error())) continue } } else { // CDRs listening on IP - if _, err := self.httpClient.PostForm(fmt.Sprintf("http://%s/cgr", self.cgrCfg.HTTPListen), storedCdr.AsHttpForm()); err != nil { + if _, err := self.httpClient.PostForm(fmt.Sprintf("http://%s/cgr", self.cdrsAddress), storedCdr.AsHttpForm()); err != nil { engine.Logger.Err(fmt.Sprintf(" Failed posting CDR, error: %s", err.Error())) continue } } } // Finished with file, move it to processed folder - newPath := path.Join(self.cgrCfg.CdrcCdrOutDir, fn) + newPath := path.Join(self.cdrOutDir, fn) if err := os.Rename(filePath, newPath); err != nil { engine.Logger.Err(err.Error()) return err diff --git a/cdrc/cdrc_local_test.go b/cdrc/cdrc_local_test.go index cebca12d6..dd448a141 100644 --- a/cdrc/cdrc_local_test.go +++ b/cdrc/cdrc_local_test.go @@ -144,7 +144,8 @@ func TestProcessCdrDir(t *testing.T) { if err := startEngine(); err != nil { t.Fatal(err.Error()) } - cdrc, err := NewCdrc(cfg, nil) + cdrc, err := NewCdrc(cfg.CdrcCdrs, cfg.CdrcCdrType, cfg.CdrcCdrInDir, cfg.CdrcCdrOutDir, cfg.CdrcSourceId, cfg.CdrcRunDelay, + cfg.CdrcCdrFields, nil) if err != nil { t.Fatal(err.Error()) } diff --git a/cdrc/cdrc_test.go b/cdrc/cdrc_test.go index 620b9fd86..187353cd7 100644 --- a/cdrc/cdrc_test.go +++ b/cdrc/cdrc_test.go @@ -19,6 +19,7 @@ along with this program. If not, see package cdrc import ( + "github.com/cgrates/cgrates/cdrs" "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" "reflect" @@ -29,7 +30,8 @@ import ( func TestRecordForkCdr(t *testing.T) { cgrConfig, _ := config.NewDefaultCGRConfig() cgrConfig.CdrcCdrFields["supplier"] = &utils.RSRField{Id: "11"} - cdrc := &Cdrc{cgrCfg: cgrConfig} + cdrc := &Cdrc{cgrConfig.CdrcCdrs, cgrConfig.CdrcCdrType, cgrConfig.CdrcCdrInDir, cgrConfig.CdrcCdrOutDir, cgrConfig.CdrcSourceId, cgrConfig.CdrcRunDelay, + cgrConfig.CdrcCdrFields, new(cdrs.CDRS), nil} cdrRow := []string{"firstField", "secondField"} _, err := cdrc.recordForkCdr(cdrRow) if err == nil { diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 4ef4fb7c4..91de929fc 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -123,11 +123,12 @@ func startMediator(responder *engine.Responder, loggerDb engine.LogStorage, cdrD close(chanDone) } -func startCdrc(cdrsChan chan struct{}) { - if cfg.CdrcCdrs == utils.INTERNAL { +// Fires up a cdrc instance +func startCdrc(cdrsChan chan struct{}, cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId string, runDelay time.Duration, cdrFields map[string]*utils.RSRField) { + if cdrsAddress == utils.INTERNAL { <-cdrsChan // Wait for CDRServer to come up before start processing } - cdrc, err := cdrc.NewCdrc(cfg, cdrServer) + cdrc, err := cdrc.NewCdrc(cdrsAddress, cdrType, cdrInDir, cdrOutDir, cdrSourceId, runDelay, cdrFields, cdrServer) if err != nil { engine.Logger.Crit(fmt.Sprintf("Cdrc config parsing error: %s", err.Error())) exitChan <- true @@ -452,10 +453,23 @@ func main() { // close all sessions on shutdown go shutdownSessionmanagerSingnalHandler() } - - if cfg.CdrcEnabled { + var cdrcEnabled bool + if cfg.CdrcEnabled { // Start default cdrc configured in csv here + cdrcEnabled = true + go startCdrc(cdrsChan, cfg.CdrcCdrs, cfg.CdrcCdrType, cfg.CdrcCdrInDir, cfg.CdrcCdrOutDir, cfg.CdrcSourceId, cfg.CdrcRunDelay, cfg.CdrcCdrFields) + } + if cfg.XmlCfgDocument != nil { + for _, xmlCdrc := range cfg.XmlCfgDocument.GetCdrcCfgs("") { + if !xmlCdrc.Enabled { + continue + } + cdrcEnabled = true + go startCdrc(cdrsChan, xmlCdrc.CdrsAddress, xmlCdrc.CdrType, xmlCdrc.CdrInDir, + xmlCdrc.CdrOutDir, xmlCdrc.CdrSourceId, time.Duration(xmlCdrc.RunDelay), xmlCdrc.CdrRSRFields()) + } + } + if cdrcEnabled { engine.Logger.Info("Starting CGRateS CDR client.") - go startCdrc(cdrsChan) } // Start the servers diff --git a/config/config.go b/config/config.go index 0dd771d05..03b6c88d9 100644 --- a/config/config.go +++ b/config/config.go @@ -438,10 +438,8 @@ func loadConfig(c *conf.ConfigFile) (*CGRConfig, error) { cfg.CdreExportedFields = extraFields } } else if strings.HasPrefix(exportTemplate, utils.XML_PROFILE_PREFIX) { - if xmlTemplate, err := cfg.XmlCfgDocument.GetCdreFWCfg(exportTemplate[len(utils.XML_PROFILE_PREFIX):]); err != nil { - return nil, err - } else { - cfg.CdreFWXmlTemplate = xmlTemplate + if xmlTemplate := cfg.XmlCfgDocument.GetCdreFWCfgs(exportTemplate[len(utils.XML_PROFILE_PREFIX):]); xmlTemplate != nil { + cfg.CdreFWXmlTemplate = xmlTemplate[exportTemplate[len(utils.XML_PROFILE_PREFIX):]] } } } diff --git a/config/config_local_test.go b/config/config_local_test.go index 23e6090a8..5461126af 100644 --- a/config/config_local_test.go +++ b/config/config_local_test.go @@ -39,9 +39,7 @@ func TestLoadXmlCfg(t *testing.T) { if cfg.XmlCfgDocument == nil { t.Error("Did not load the XML Config Document") } - if cdreFWCfg, err := cfg.XmlCfgDocument.GetCdreFWCfg("CDREFW-A"); err != nil { - t.Error(err) - } else if cdreFWCfg == nil { + if cdreFWCfg := cfg.XmlCfgDocument.GetCdreFWCfgs("CDREFW-A"); cdreFWCfg == nil { t.Error("Could not retrieve CDRExporter FixedWidth config instance") } } diff --git a/config/xmlcdrc.go b/config/xmlcdrc.go index ea2ad43b9..b056dd353 100644 --- a/config/xmlcdrc.go +++ b/config/xmlcdrc.go @@ -24,26 +24,33 @@ import ( ) type CgrXmlCdrcCfg struct { - Enabled bool `xml:"enabled"` // Enable/Disable the - CdrsAddress string `xml:"cdrs_address"` // The address where CDRs can be reached - CdrsMethod string `xml:"cdrs_method"` // Method to use when posting CDRs - CdrType string `xml:"cdr_type"` // The type of CDR to process - RunDelay int64 `xml:"run_delay"` // Delay between runs - CdrInDir string `xml:"cdr_in_dir"` // Folder to process CDRs from - CdrOutDir string `xml:"cdr_out_dir"` // Folder to move processed CDRs to - CdrSourceId string `xml:"cdr_source_id"` // Source identifier for the processed CDRs - CdrFields []CdrcField `xml:"fields>field"` + Enabled bool `xml:"enabled"` // Enable/Disable the + CdrsAddress string `xml:"cdrs_address"` // The address where CDRs can be reached + CdrType string `xml:"cdr_type"` // The type of CDR to process + RunDelay int64 `xml:"run_delay"` // Delay between runs + CdrInDir string `xml:"cdr_in_dir"` // Folder to process CDRs from + CdrOutDir string `xml:"cdr_out_dir"` // Folder to move processed CDRs to + CdrSourceId string `xml:"cdr_source_id"` // Source identifier for the processed CDRs + CdrFields []*CdrcField `xml:"fields>field"` +} + +func (cdrcCfg *CgrXmlCdrcCfg) CdrRSRFields() map[string]*utils.RSRField { + rsrFields := make(map[string]*utils.RSRField) + for _, fld := range cdrcCfg.CdrFields { + rsrFields[fld.Id] = fld.rsrField + } + return rsrFields } type CdrcField struct { XMLName xml.Name `xml:"field"` Id string `xml:"id,attr"` Filter string `xml:"filter,attr"` - RSRField *utils.RSRField + rsrField *utils.RSRField } -func (cdrcFld *CdrcField) PopulateRSRFIeld() (err error) { - if cdrcFld.RSRField, err = utils.NewRSRField(cdrcFld.Filter); err != nil { +func (cdrcFld *CdrcField) PopulateRSRField() (err error) { + if cdrcFld.rsrField, err = utils.NewRSRField(cdrcFld.Filter); err != nil { return err } return nil diff --git a/config/xmlcdrc_test.go b/config/xmlcdrc_test.go index 140eb2d1a..81392f7d1 100644 --- a/config/xmlcdrc_test.go +++ b/config/xmlcdrc_test.go @@ -30,15 +30,15 @@ var cfgDocCdrc *CgrXmlCfgDocument // Will be populated by first test func TestPopulateRSRFIeld(t *testing.T) { cdrcField := CdrcField{Id: "TEST1", Filter: `~effective_caller_id_number:s/(\d+)/+$1/`} - if err := cdrcField.PopulateRSRFIeld(); err != nil { + if err := cdrcField.PopulateRSRField(); err != nil { t.Error("Unexpected error: ", err.Error()) - } else if cdrcField.RSRField == nil { + } else if cdrcField.rsrField == nil { t.Error("Failed loading the RSRField") } - cdrcField = CdrcField{Id: "TEST2", Filter: `1`} - if err := cdrcField.PopulateRSRFIeld(); err != nil { + cdrcField = CdrcField{Id: "TEST2", Filter: `99`} + if err := cdrcField.PopulateRSRField(); err != nil { t.Error("Unexpected error: ", err.Error()) - } else if cdrcField.RSRField == nil { + } else if cdrcField.rsrField == nil { t.Error("Failed loading the RSRField") } } @@ -49,7 +49,6 @@ func TestParseXmlCdrcConfig(t *testing.T) { true internal - http_cgr csv 0 /var/log/cgrates/cdrc/in @@ -84,33 +83,57 @@ func TestParseXmlCdrcConfig(t *testing.T) { } } -func TestGetCdrcCfg(t *testing.T) { - cdrcfg, err := cfgDocCdrc.GetCdrcCfg("CDRC-CSV1") - if err != nil { - t.Error("Unexpected error: ", err) - } else if cdrcfg == nil { +func TestGetCdrcCfgs(t *testing.T) { + cdrcfgs := cfgDocCdrc.GetCdrcCfgs("CDRC-CSV1") + if cdrcfgs == nil { t.Error("No config instance returned") } - expectCdrc := &CgrXmlCdrcCfg{Enabled: true, CdrsAddress: "internal", CdrsMethod: "http_cgr", CdrType: "csv", + expectCdrc := &CgrXmlCdrcCfg{Enabled: true, CdrsAddress: "internal", CdrType: "csv", RunDelay: 0, CdrInDir: "/var/log/cgrates/cdrc/in", CdrOutDir: "/var/log/cgrates/cdrc/out", CdrSourceId: "freeswitch_csv"} - cdrFlds := []CdrcField{CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCID, Filter: "0"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.REQTYPE, Filter: "1"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DIRECTION, Filter: "2"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.TENANT, Filter: "3"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.CATEGORY, Filter: "4"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCOUNT, Filter: "5"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.SUBJECT, Filter: "6"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DESTINATION, Filter: "7"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.SETUP_TIME, Filter: "8"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ANSWER_TIME, Filter: "9"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.USAGE, Filter: "10"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr1", Filter: "11"}, - CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr2", Filter: "12"}} + cdrFlds := []*CdrcField{ + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCID, Filter: "0"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.REQTYPE, Filter: "1"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DIRECTION, Filter: "2"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.TENANT, Filter: "3"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.CATEGORY, Filter: "4"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCOUNT, Filter: "5"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.SUBJECT, Filter: "6"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DESTINATION, Filter: "7"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.SETUP_TIME, Filter: "8"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ANSWER_TIME, Filter: "9"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.USAGE, Filter: "10"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr1", Filter: "11"}, + &CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr2", Filter: "12"}} for _, fld := range cdrFlds { - fld.PopulateRSRFIeld() + fld.PopulateRSRField() } expectCdrc.CdrFields = cdrFlds - if !reflect.DeepEqual(expectCdrc, cdrcfg) { - t.Errorf("Expecting: %v, received: %v", expectCdrc, cdrcfg) + if !reflect.DeepEqual(expectCdrc, cdrcfgs["CDRC-CSV1"]) { + t.Errorf("Expecting: %v, received: %v", expectCdrc, cdrcfgs["CDRC-CSV1"]) + } +} + +func TestCdrRSRFields(t *testing.T) { + cdrcfgs := cfgDocCdrc.GetCdrcCfgs("CDRC-CSV1") + if cdrcfgs == nil { + t.Error("No config instance returned") + } + eRSRFields := map[string]*utils.RSRField{ + utils.ACCID: &utils.RSRField{Id: "0"}, + utils.REQTYPE: &utils.RSRField{Id: "1"}, + utils.DIRECTION: &utils.RSRField{Id: "2"}, + utils.TENANT: &utils.RSRField{Id: "3"}, + utils.CATEGORY: &utils.RSRField{Id: "4"}, + utils.ACCOUNT: &utils.RSRField{Id: "5"}, + utils.SUBJECT: &utils.RSRField{Id: "6"}, + utils.DESTINATION: &utils.RSRField{Id: "7"}, + utils.SETUP_TIME: &utils.RSRField{Id: "8"}, + utils.ANSWER_TIME: &utils.RSRField{Id: "9"}, + utils.USAGE: &utils.RSRField{Id: "10"}, + "extr1": &utils.RSRField{Id: "11"}, + "extr2": &utils.RSRField{Id: "12"}, + } + if rsrFields := cdrcfgs["CDRC-CSV1"].CdrRSRFields(); !reflect.DeepEqual(rsrFields, eRSRFields) { + t.Errorf("Expecting: %v, received: %v", eRSRFields, rsrFields) } } diff --git a/config/xmlcdre_test.go b/config/xmlcdre_test.go index 7840b402a..d6568d1d4 100644 --- a/config/xmlcdre_test.go +++ b/config/xmlcdre_test.go @@ -93,19 +93,17 @@ func TestParseXmlConfig(t *testing.T) { } func TestGetCdreFWCfg(t *testing.T) { - cdreFWCfg, err := cfgDoc.GetCdreFWCfg("CDRE-FW1") - if err != nil { - t.Error(err) - } else if cdreFWCfg == nil { + cdreFWCfg := cfgDoc.GetCdreFWCfgs("CDRE-FW1") + if cdreFWCfg == nil { t.Error("Could not parse CdreFw instance") } - if len(cdreFWCfg.Header.Fields) != 8 { - t.Error("Unexpected number of header fields parsed", len(cdreFWCfg.Header.Fields)) + if len(cdreFWCfg["CDRE-FW1"].Header.Fields) != 8 { + t.Error("Unexpected number of header fields parsed", len(cdreFWCfg["CDRE-FW1"].Header.Fields)) } - if len(cdreFWCfg.Content.Fields) != 20 { - t.Error("Unexpected number of content fields parsed", len(cdreFWCfg.Content.Fields)) + if len(cdreFWCfg["CDRE-FW1"].Content.Fields) != 20 { + t.Error("Unexpected number of content fields parsed", len(cdreFWCfg["CDRE-FW1"].Content.Fields)) } - if len(cdreFWCfg.Trailer.Fields) != 9 { - t.Error("Unexpected number of trailer fields parsed", len(cdreFWCfg.Trailer.Fields)) + if len(cdreFWCfg["CDRE-FW1"].Trailer.Fields) != 9 { + t.Error("Unexpected number of trailer fields parsed", len(cdreFWCfg["CDRE-FW1"].Trailer.Fields)) } } diff --git a/config/xmlconfig.go b/config/xmlconfig.go index 585b30587..ed628cdc9 100644 --- a/config/xmlconfig.go +++ b/config/xmlconfig.go @@ -106,7 +106,7 @@ func (xmlCfg *CgrXmlCfgDocument) cacheCdrcCfgs() error { } // Cache rsr fields for _, fld := range cdrcCfg.CdrFields { - if err := fld.PopulateRSRFIeld(); err != nil { + if err := fld.PopulateRSRField(); err != nil { return fmt.Errorf("Populating field %s, error: %s", fld.Id, err.Error()) } } @@ -115,18 +115,26 @@ func (xmlCfg *CgrXmlCfgDocument) cacheCdrcCfgs() error { return nil } -func (xmlCfg *CgrXmlCfgDocument) GetCdreFWCfg(instName string) (*CgrXmlCdreFwCfg, error) { - if cfg, hasIt := xmlCfg.cdrefws[instName]; !hasIt { - return nil, nil - } else { - return cfg, nil +// Return instances or filtered instance of cdrefw configuration +func (xmlCfg *CgrXmlCfgDocument) GetCdreFWCfgs(instName string) map[string]*CgrXmlCdreFwCfg { + if len(instName) != 0 { + if cfg, hasIt := xmlCfg.cdrefws[instName]; !hasIt { + return nil + } else { + return map[string]*CgrXmlCdreFwCfg{instName: cfg} + } } + return xmlCfg.cdrefws } -func (xmlCfg *CgrXmlCfgDocument) GetCdrcCfg(instName string) (*CgrXmlCdrcCfg, error) { - if cfg, hasIt := xmlCfg.cdrcs[instName]; !hasIt { - return nil, nil - } else { - return cfg, nil +// Return instances or filtered instance of cdrc configuration +func (xmlCfg *CgrXmlCfgDocument) GetCdrcCfgs(instName string) map[string]*CgrXmlCdrcCfg { + if len(instName) != 0 { + if cfg, hasIt := xmlCfg.cdrcs[instName]; !hasIt { + return nil + } else { + return map[string]*CgrXmlCdrcCfg{instName: cfg} // Filtered + } } + return xmlCfg.cdrcs // Unfiltered } diff --git a/data/conf/cgrates.cfg b/data/conf/cgrates.cfg index e381988d3..4b81be78b 100644 --- a/data/conf/cgrates.cfg +++ b/data/conf/cgrates.cfg @@ -32,7 +32,7 @@ # default_tenant = cgrates.org # Default Tenant to consider when missing from requests. # default_subject = cgrates # Default rating Subject to consider when missing from requests. # rounding_method = *middle # Rounding method for floats/costs: <*up|*middle|*down> -# rounding_decimals = 4 # Number of decimals to round float/costs at +# rounding_decimals = 10 # Number of decimals to round float/costs at # xmlcfg_path = # Path towards additional config defined in xml file [balancer] @@ -61,7 +61,6 @@ [cdrc] # enabled = false # Enable CDR client functionality # cdrs = internal # Address where to reach CDR server. -# cdrs_method = http_cgr # Mechanism to use when posting CDRs on server # run_delay = 0 # Sleep interval in seconds between consecutive runs, 0 to use automation via inotify # cdr_type = csv # CDR file format . # cdr_in_dir = /var/log/cgrates/cdrc/in # Absolute path towards the directory where the CDRs are stored. diff --git a/data/tutorials/fs_csv/cgrates/etc/cgrates/cgrates.cfg b/data/tutorials/fs_csv/cgrates/etc/cgrates/cgrates.cfg index 948f16fa1..ee4126b89 100644 --- a/data/tutorials/fs_csv/cgrates/etc/cgrates/cgrates.cfg +++ b/data/tutorials/fs_csv/cgrates/etc/cgrates/cgrates.cfg @@ -58,7 +58,6 @@ export_dir = /tmp/cgrates/cdre # Path where the exported CDRs will be placed [cdrc] enabled = true # Enable CDR client functionality # cdrs = internal # Address where to reach CDR server. -# cdrs_method = http_cgr # Mechanism to use when posting CDRs on server # run_delay = 0 # Sleep interval in seconds between consecutive runs, 0 to use automation via inotify cdr_type = freeswitch_csv # CDR file format . cdr_in_dir = /tmp/cgrates/cdr/cdrc/in # Absolute path towards the directory where the CDRs are stored.