Add RPCConns section in config

This commit is contained in:
TeoV
2019-11-28 17:28:52 +02:00
parent 29c950f495
commit f8ad80eae0
9 changed files with 318 additions and 78 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 := "<Stats> not enabled but requested by <RALs> 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 = "<ThresholdS> not enabled but requested by <RALs> 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 = "<Chargers> not enabled but requested by <CDRs> 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 = "<RALs> not enabled but requested by <CDRs> 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 = "<AttributeS> not enabled but requested by <CDRs> 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 = "<StatS> not enabled but requested by <CDRs> 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 = "<CDRs> Cannot find CDR export template with ID: <stringy>"
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 = "<cdrc> 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 = "<CDRs> not enabled but referenced from <cdrc>"
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 = "<cdrc> 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)
}
}

View File

@@ -256,7 +256,7 @@ type FsConnJsonCfg struct {
Alias *string
}
type RpcConnsJson struct {
type RPCConnsJson struct {
Strategy *string
PoolSize *int
Conns *[]*RemoteHostJson

81
config/rpcconn.go Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>
*/
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
}

19
config/rpcconn_test.go Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>
*/
package config

View File

@@ -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 {

View File

@@ -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"