diff --git a/config/config.go b/config/config.go index a22995c32..8f988d430 100755 --- a/config/config.go +++ b/config/config.go @@ -31,6 +31,8 @@ import ( "sync" "time" + "github.com/cgrates/rpcclient" + "github.com/cgrates/cgrates/utils" ) @@ -134,7 +136,7 @@ func NewDefaultCGRConfig() (cfg *CGRConfig, err error) { cfg.DataFolderPath = "/usr/share/cgrates/" cfg.MaxCallDuration = time.Duration(3) * time.Hour // Hardcoded for now - cfg.rpcConns = make(map[string]*RpcConn) + cfg.rpcConns = make(map[string]*RPCConn) cfg.generalCfg = new(GeneralCfg) cfg.generalCfg.NodeID = utils.UUIDSha1Prefix() cfg.dataDbCfg = new(DataDbCfg) @@ -257,7 +259,7 @@ type CGRConfig struct { ConfigReloads map[string]chan struct{} // Signals to specific entities that a config reload should occur rldChans map[string]chan struct{} // index here the channels used for reloads - rpcConns map[string]*RpcConn + rpcConns map[string]*RPCConn generalCfg *GeneralCfg // General config dataDbCfg *DataDbCfg // Database config @@ -321,7 +323,7 @@ func (cfg *CGRConfig) LazySanityCheck() { func (cfg *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { // Load sections out of JSON config, stop on error for _, loadFunc := range []func(*CgrJsonCfg) error{ - cfg.loadRpcConns, + cfg.loadRPCConns, cfg.loadGeneralCfg, cfg.loadCacheCfg, cfg.loadListenCfg, cfg.loadHttpCfg, cfg.loadDataDBCfg, cfg.loadStorDBCfg, cfg.loadFilterSCfg, cfg.loadRalSCfg, cfg.loadSchedulerCfg, @@ -341,12 +343,37 @@ func (cfg *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { return } -// loadRpcConns loads the RPCConns section of the configuration -func (cfg *CGRConfig) loadRpcConns(jsnCfg *CgrJsonCfg) (err error) { - //var jsnRpcConns map[string]*RpcConnsJson - //if jsnRpcConns, err = jsnCfg.RpcConnJsonCfg(); err != nil { - // return - //} +// loadRPCConns loads the RPCConns section of the configuration +func (cfg *CGRConfig) loadRPCConns(jsnCfg *CgrJsonCfg) (err error) { + var jsnRpcConns map[string]*RPCConnsJson + if jsnRpcConns, err = jsnCfg.RPCConnJsonCfg(); err != nil { + return + } + // hardoded the *internal and *localhost connections + cfg.rpcConns[utils.MetaInternal] = &RPCConn{ + Strategy: rpcclient.POOL_FIRST, + PoolSize: 0, + Conns: []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + }, + } + cfg.rpcConns[utils.MetaLocalHost] = &RPCConn{ + Strategy: rpcclient.POOL_FIRST, + PoolSize: 0, + Conns: []*RemoteHost{ + &RemoteHost{ + Address: "127.0.0.1:2012", + Transport: utils.MetaJSONrpc, + }, + }, + } + for key, val := range jsnRpcConns { + if err = cfg.rpcConns[key].loadFromJsonCfg(val); err != nil { + return + } + } return } diff --git a/config/config_defaults.go b/config/config_defaults.go index a4c0b40df..fb6c5bac1 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -53,6 +53,9 @@ const CGRATES_CFG_JSON = ` }, +"rpc_conns": {}, // rpc connections definitions + + "data_db": { // database used to store runtime data (eg: accounts) "db_type": "*redis", // data_db type: <*redis|*mongo> "db_host": "127.0.0.1", // data_db host address diff --git a/config/config_json.go b/config/config_json.go index 184656813..7441ecdcd 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -39,7 +39,6 @@ const ( FreeSWITCHAgentJSN = "freeswitch_agent" KamailioAgentJSN = "kamailio_agent" AsteriskAgentJSN = "asterisk_agent" - OSIPS_JSN = "opensips" DA_JSN = "diameter_agent" RA_JSN = "radius_agent" HttpAgentJson = "http_agent" @@ -60,7 +59,7 @@ const ( Apier = "apier" DNSAgentJson = "dns_agent" ERsJson = "ers" - RpcConnsJsonName = "rpc_conns" + RPCConnsJsonName = "rpc_conns" ) // Loads the json config out of io.Reader, eg other sources than file, maybe over http @@ -85,13 +84,13 @@ func (self CgrJsonCfg) GeneralJsonCfg() (*GeneralJsonCfg, error) { return cfg, nil } -func (self CgrJsonCfg) RpcConnJsonCfg() (map[string]*RpcConnsJson, error) { - rawCfg, hasKey := self[RpcConnsJsonName] +func (self CgrJsonCfg) RPCConnJsonCfg() (map[string]*RPCConnsJson, error) { + rawCfg, hasKey := self[RPCConnsJsonName] if !hasKey { return nil, nil } - cfg := make(map[string]*RpcConnsJson) - if err := json.Unmarshal(*rawCfg, cfg); err != nil { + cfg := make(map[string]*RPCConnsJson) + if err := json.Unmarshal(*rawCfg, &cfg); err != nil { return nil, err } return cfg, nil diff --git a/config/config_test.go b/config/config_test.go index 7c93ffa2d..6c30e647c 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -23,6 +23,8 @@ import ( "testing" "time" + "github.com/cgrates/rpcclient" + "github.com/cgrates/cgrates/utils" ) @@ -1910,3 +1912,173 @@ func TestCgrCfgEventReaderDefault(t *testing.T) { } } + +func TestRpcConnsDefaults(t *testing.T) { + eCfg := make(map[string]*RPCConn) + // hardoded the *internal and *localhost connections + eCfg[utils.MetaInternal] = &RPCConn{ + Strategy: rpcclient.POOL_FIRST, + PoolSize: 0, + Conns: []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + }, + } + eCfg[utils.MetaLocalHost] = &RPCConn{ + Strategy: rpcclient.POOL_FIRST, + PoolSize: 0, + Conns: []*RemoteHost{ + &RemoteHost{ + Address: "127.0.0.1:2012", + Transport: utils.MetaJSONrpc, + }, + }, + } + if !reflect.DeepEqual(cgrCfg.rpcConns, eCfg) { + t.Errorf("received: %+v,\n expecting: %+v", utils.ToJSON(cgrCfg.rpcConns), utils.ToJSON(eCfg)) + } +} + +func TestCheckConfigSanity(t *testing.T) { + // Rater checks + cfg, _ := NewDefaultCGRConfig() + cfg.ralsCfg = &RalsCfg{ + Enabled: true, + StatSConns: []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + }, + } + expected := " not enabled but requested by component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.statsCfg.Enabled = true + cfg.ralsCfg.ThresholdSConns = []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + } + expected = " not enabled but requested by component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.ralsCfg = &RalsCfg{ + Enabled: false, + StatSConns: []*RemoteHost{}, + ThresholdSConns: []*RemoteHost{}, + } + // CDRServer checks + cfg.thresholdSCfg.Enabled = true + cfg.cdrsCfg = &CdrsCfg{ + Enabled: true, + ChargerSConns: []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + }, + } + expected = " not enabled but requested by component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.chargerSCfg.Enabled = true + cfg.cdrsCfg.RaterConns = []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + } + expected = " not enabled but requested by component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.ralsCfg.Enabled = true + cfg.cdrsCfg.AttributeSConns = []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + } + expected = " not enabled but requested by component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.statsCfg.Enabled = false + cfg.attributeSCfg.Enabled = true + cfg.cdrsCfg.StatSConns = []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + } + expected = " not enabled but requested by component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.statsCfg.Enabled = true + cfg.cdrsCfg.OnlineCDRExports = []string{"stringy"} + cfg.CdreProfiles = map[string]*CdreCfg{"stringx": &CdreCfg{}} + expected = " Cannot find CDR export template with ID: " + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.thresholdSCfg.Enabled = false + cfg.cdrsCfg.OnlineCDRExports = []string{"stringx"} + cfg.cdrsCfg.ThresholdSConns = []*RemoteHost{ + &RemoteHost{ + Address: utils.MetaInternal, + }, + } + expected = "ThresholdS not enabled but requested by CDRs component." + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + // CDRC sanity checks + cfg, _ = NewDefaultCGRConfig() + cfg.CdrcProfiles = map[string][]*CdrcCfg{ + "test": []*CdrcCfg{ + &CdrcCfg{ + Enabled: true, + }, + }, + } + expected = " Instance: , cdrc enabled but no CDRs defined!" + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + cfg.dispatcherSCfg.Enabled = false + cfg.CdrcProfiles = map[string][]*CdrcCfg{ + "test": []*CdrcCfg{ + &CdrcCfg{ + Enabled: true, + CdrsConns: []*RemoteHost{ + &RemoteHost{Address: utils.MetaInternal}, + }, + }, + }, + } + expected = " not enabled but referenced from " + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } + + cfg.CdrcProfiles = map[string][]*CdrcCfg{ + "test": []*CdrcCfg{ + &CdrcCfg{ + Enabled: true, + CdrsConns: []*RemoteHost{ + &RemoteHost{Address: utils.MetaInternal}, + }, + ContentFields: []*FCTemplate{}, + }, + }, + } + cfg.cdrsCfg = &CdrsCfg{ + Enabled: true, + } + + expected = " enabled but no fields to be processed defined!" + if err := cfg.checkConfigSanity(); err == nil || err.Error() != expected { + t.Errorf("Expecting: %+q received: %+q", expected, err) + } +} diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 9b7bf33c5..faeff6c01 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -256,7 +256,7 @@ type FsConnJsonCfg struct { Alias *string } -type RpcConnsJson struct { +type RPCConnsJson struct { Strategy *string PoolSize *int Conns *[]*RemoteHostJson diff --git a/config/rpcconn.go b/config/rpcconn.go new file mode 100644 index 000000000..a6c3a96bb --- /dev/null +++ b/config/rpcconn.go @@ -0,0 +1,81 @@ +/* +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 config + +// Returns the first cached default value for a RemoteHost connection +func NewDfltRemoteHost() *RemoteHost { + if dfltRemoteHost == nil { + return new(RemoteHost) // No defaults, most probably we are building the defaults now + } + dfltVal := *dfltRemoteHost // Copy the value instead of it's pointer + return &dfltVal +} + +type RPCConn struct { + Strategy string + PoolSize int + Conns []*RemoteHost +} + +func (rC *RPCConn) loadFromJsonCfg(jsnCfg *RPCConnsJson) (err error) { + if jsnCfg == nil { + return + } + if jsnCfg.Strategy != nil { + rC.Strategy = *jsnCfg.Strategy + } + if jsnCfg.PoolSize != nil { + rC.PoolSize = *jsnCfg.PoolSize + } + if jsnCfg.Conns != nil { + rC.Conns = make([]*RemoteHost, len(*jsnCfg.Conns)) + for idx, jsnHaCfg := range *jsnCfg.Conns { + rC.Conns[idx] = NewDfltRemoteHost() + rC.Conns[idx].loadFromJsonCfg(jsnHaCfg) + } + } + return +} + +// One connection to Rater +type RemoteHost struct { + Address string + Transport string + Synchronous bool + TLS bool +} + +func (self *RemoteHost) loadFromJsonCfg(jsnCfg *RemoteHostJson) error { + if jsnCfg == nil { + return nil + } + if jsnCfg.Address != nil { + self.Address = *jsnCfg.Address + } + if jsnCfg.Transport != nil { + self.Transport = *jsnCfg.Transport + } + if jsnCfg.Synchronous != nil { + self.Synchronous = *jsnCfg.Synchronous + } + if jsnCfg.Tls != nil { + self.TLS = *jsnCfg.Tls + } + return nil +} diff --git a/config/rpcconn_test.go b/config/rpcconn_test.go new file mode 100644 index 000000000..6d55b49ee --- /dev/null +++ b/config/rpcconn_test.go @@ -0,0 +1,19 @@ +/* +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 config diff --git a/config/smconfig.go b/config/smconfig.go index 67bb866ba..00a011435 100644 --- a/config/smconfig.go +++ b/config/smconfig.go @@ -24,68 +24,6 @@ import ( "github.com/cgrates/cgrates/utils" ) -// Returns the first cached default value for a FreeSWITCHAgent connection -func NewDfltRemoteHost() *RemoteHost { - if dfltRemoteHost == nil { - return new(RemoteHost) // No defaults, most probably we are building the defaults now - } - dfltVal := *dfltRemoteHost // Copy the value instead of it's pointer - return &dfltVal -} - -type RpcConn struct { - Strategy string - PoolSize int - Conns []*RemoteHost -} - -func (rC *RpcConn) loadFromJsonCfg(jsnCfg *RpcConnsJson) (err error) { - if jsnCfg == nil { - return - } - if jsnCfg.Strategy != nil { - rC.Strategy = *jsnCfg.Strategy - } - if jsnCfg.PoolSize != nil { - rC.PoolSize = *jsnCfg.PoolSize - } - if jsnCfg.Conns != nil { - rC.Conns = make([]*RemoteHost, len(*jsnCfg.Conns)) - for idx, jsnHaCfg := range *jsnCfg.Conns { - rC.Conns[idx] = NewDfltRemoteHost() - rC.Conns[idx].loadFromJsonCfg(jsnHaCfg) - } - } - return -} - -// One connection to Rater -type RemoteHost struct { - Address string - Transport string - Synchronous bool - TLS bool -} - -func (self *RemoteHost) loadFromJsonCfg(jsnCfg *RemoteHostJson) error { - if jsnCfg == nil { - return nil - } - if jsnCfg.Address != nil { - self.Address = *jsnCfg.Address - } - if jsnCfg.Transport != nil { - self.Transport = *jsnCfg.Transport - } - if jsnCfg.Synchronous != nil { - self.Synchronous = *jsnCfg.Synchronous - } - if jsnCfg.Tls != nil { - self.TLS = *jsnCfg.Tls - } - return nil -} - // Returns the first cached default value for a FreeSWITCHAgent connection func NewDfltFsConnConfig() *FsConnCfg { if dfltFsConnConfig == nil { diff --git a/utils/consts.go b/utils/consts.go index b828a9dbb..50f0c0277 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -193,6 +193,7 @@ const ( DRYRUN = "dry_run" META_COMBIMED = "*combimed" MetaInternal = "*internal" + MetaLocalHost = "*localhost" ZERO_RATING_SUBJECT_PREFIX = "*zero" OK = "OK" MetaFileXML = "*file_xml"