From 3075b70d0b43c42f0d799ad37510845791f607d9 Mon Sep 17 00:00:00 2001 From: TeoV Date: Thu, 18 Apr 2019 12:23:57 +0300 Subject: [PATCH] Add ConfigSv1 in Dispatcher --- apier/v1/config.go | 43 ++++++++++ apier/v1/dispatcher.go | 15 ++++ cmd/cgr-engine/cgr-engine.go | 17 ++++ config/config.go | 90 +++++++++++++++++++++ config/config_test.go | 27 +++++++ console/get_json_section.go | 66 +++++++++++++++ data/tariffplans/dispatchers/Attributes.csv | 1 + dispatchers/config.go | 40 +++++++++ dispatchers/config_it_test.go | 63 +++++++++++++++ utils/consts.go | 6 ++ 10 files changed, 368 insertions(+) create mode 100644 apier/v1/config.go create mode 100644 console/get_json_section.go create mode 100644 dispatchers/config.go create mode 100644 dispatchers/config_it_test.go diff --git a/apier/v1/config.go b/apier/v1/config.go new file mode 100644 index 000000000..6ca5b2a47 --- /dev/null +++ b/apier/v1/config.go @@ -0,0 +1,43 @@ +/* +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 v1 + +import ( + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" +) + +func NewConfigSv1(cfg *config.CGRConfig) *ConfigSv1 { + return &ConfigSv1{cfg: cfg} +} + +// Exports RPC from ConfigSv1 +type ConfigSv1 struct { + cfg *config.CGRConfig +} + +func (cSv1 *ConfigSv1) GetJSONSection(section *config.StringWithArgDispatcher, reply *map[string]interface{}) (err error) { + return cSv1.cfg.V1GetConfigSection(section, reply) +} + +// Call implements rpcclient.RpcClientConnection interface for internal RPC +func (cSv1 *ConfigSv1) Call(serviceMethod string, + args interface{}, reply interface{}) error { + return utils.APIerRPCCall(cSv1, serviceMethod, args, reply) +} diff --git a/apier/v1/dispatcher.go b/apier/v1/dispatcher.go index 9a1cd4869..40cec93e8 100755 --- a/apier/v1/dispatcher.go +++ b/apier/v1/dispatcher.go @@ -21,6 +21,7 @@ package v1 import ( "time" + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/dispatchers" "github.com/cgrates/cgrates/engine" "github.com/cgrates/cgrates/sessions" @@ -744,3 +745,17 @@ func (dS *DispatcherSServiceManagerV1) StopService(args dispatchers.ArgStartServ func (dS *DispatcherSServiceManagerV1) ServiceStatus(args dispatchers.ArgStartServiceWithApiKey, reply *string) error { return dS.dS.ServiceManagerV1ServiceStatus(args, reply) } + +func NewDispatcherConfigSv1(dps *dispatchers.DispatcherService) *DispatcherConfigSv1 { + return &DispatcherConfigSv1{dS: dps} +} + +// Exports RPC from CDRsV1 +type DispatcherConfigSv1 struct { + dS *dispatchers.DispatcherService +} + +// Ping used to detreminate if component is active +func (dS *DispatcherConfigSv1) GetJSONSection(args *config.StringWithArgDispatcher, reply *map[string]interface{}) (err error) { + return dS.dS.ConfigSv1GetJSONSection(args, reply) +} diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 1d623c74a..2e2bb2317 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -1239,6 +1239,9 @@ func startDispatcherService(internalDispatcherSChan, internalAttributeSChan chan server.RpcRegisterName(utils.CDRsV1, v1.NewDispatcherSCDRsV1(dspS)) + server.RpcRegisterName(utils.ConfigSv1, + v1.NewDispatcherConfigSv1(dspS)) + internalDispatcherSChan <- dspS } @@ -1450,6 +1453,15 @@ func schedCDRsConns(internalCDRSChan, internalDispatcherSChan chan rpcclient.Rpc engine.SetSchedCdrsConns(cdrsConn) } +func initConfigSv1(internalConfigChan chan rpcclient.RpcClientConnection, + server *utils.Server) { + cfgSv1 := v1.NewConfigSv1(cfg) + if !cfg.DispatcherSCfg().Enabled { + server.RpcRegister(cfgSv1) + } + internalConfigChan <- cfgSv1 +} + func memProfFile(memProfPath string) bool { f, err := os.Create(memProfPath) if err != nil { @@ -1638,6 +1650,7 @@ func main() { internalApierV1Chan := make(chan rpcclient.RpcClientConnection, 1) internalApierV2Chan := make(chan rpcclient.RpcClientConnection, 1) internalServeManagerChan := make(chan rpcclient.RpcClientConnection, 1) + internalConfigChan := make(chan rpcclient.RpcClientConnection, 1) // init internalRPCSet engine.IntRPC = engine.NewRPCClientSet() @@ -1660,6 +1673,8 @@ func main() { engine.IntRPC.AddInternalRPCClient(utils.SupplierSv1, internalSupplierSChan) engine.IntRPC.AddInternalRPCClient(utils.ThresholdSv1, internalThresholdSChan) engine.IntRPC.AddInternalRPCClient(utils.ServiceManagerV1, internalServeManagerChan) + engine.IntRPC.AddInternalRPCClient(utils.ServManagerV1, internalServeManagerChan) + engine.IntRPC.AddInternalRPCClient(utils.ConfigSv1, internalConfigChan) } // init CacheS @@ -1675,6 +1690,8 @@ func main() { // init SchedulerS initSchedulerS(internalSchedSChan, srvManager, server) + initConfigSv1(internalConfigChan, server) + // Start Scheduler if cfg.SchedulerCfg().Enabled { go srvManager.StartScheduler(true) diff --git a/config/config.go b/config/config.go index 0d32a12ea..153561274 100755 --- a/config/config.go +++ b/config/config.go @@ -19,6 +19,7 @@ along with this program. If not, see package config import ( + "encoding/json" "errors" "fmt" "net/url" @@ -216,6 +217,7 @@ func NewCGRConfigFromPath(path string) (*CGRConfig, error) { if err != nil { return nil, err } + cfg.ConfigPath = path if isUrl(path) { return loadConfigFromHttp(cfg, path) // prefix protocol } @@ -296,6 +298,7 @@ func loadConfigFromHttp(cfg *CGRConfig, urlPaths string) (*CGRConfig, error) { type CGRConfig struct { MaxCallDuration time.Duration // The maximum call duration (used by responder when querying DerivedCharging) // ToDo: export it in configuration file DataFolderPath string // Path towards data folder, for tests internal usage, not loading out of .json options + ConfigPath string // Path towards config // Cache defaults loaded from json and needing clones dfltCdreProfile *CdreCfg // Default cdreConfig profile @@ -1186,3 +1189,90 @@ func (cfg *CGRConfig) AnalyzerSCfg() *AnalyzerSCfg { func (cfg *CGRConfig) ApierCfg() *ApierCfg { return cfg.apier } + +// Call implements rpcclient.RpcClientConnection interface for internal RPC +func (cSv1 *CGRConfig) Call(serviceMethod string, + args interface{}, reply interface{}) error { + return utils.APIerRPCCall(cSv1, serviceMethod, args, reply) +} + +type StringWithArgDispatcher struct { + *utils.ArgDispatcher + utils.TenantArg + Section string +} + +//V1GetConfigSection will retrieve from CGRConfig a section +func (cfg *CGRConfig) V1GetConfigSection(args *StringWithArgDispatcher, reply *map[string]interface{}) (err error) { + var jsonString string + switch args.Section { + case GENERAL_JSN: + jsonString = utils.ToJSON(cfg.GeneralCfg()) + case DATADB_JSN: + jsonString = utils.ToJSON(cfg.DataDbCfg()) + case STORDB_JSN: + jsonString = utils.ToJSON(cfg.StorDbCfg()) + case TlsCfgJson: + jsonString = utils.ToJSON(cfg.TlsCfg()) + case CACHE_JSN: + jsonString = utils.ToJSON(cfg.CacheCfg()) + case LISTEN_JSN: + jsonString = utils.ToJSON(cfg.ListenCfg()) + case HTTP_JSN: + jsonString = utils.ToJSON(cfg.HTTPCfg()) + case FILTERS_JSON: + jsonString = utils.ToJSON(cfg.FilterSCfg()) + case RALS_JSN: + jsonString = utils.ToJSON(cfg.RalsCfg()) + case SCHEDULER_JSN: + jsonString = utils.ToJSON(cfg.SchedulerCfg()) + case CDRS_JSN: + jsonString = utils.ToJSON(cfg.CdrsCfg()) + case SessionSJson: + jsonString = utils.ToJSON(cfg.SessionSCfg()) + case FS_JSN: + jsonString = utils.ToJSON(cfg.FsAgentCfg()) + case KamailioAgentJSN: + jsonString = utils.ToJSON(cfg.KamAgentCfg()) + case AsteriskAgentJSN: + jsonString = utils.ToJSON(cfg.AsteriskAgentCfg()) + case DA_JSN: + jsonString = utils.ToJSON(cfg.DiameterAgentCfg()) + case RA_JSN: + jsonString = utils.ToJSON(cfg.RadiusAgentCfg()) + case DNSAgentJson: + jsonString = utils.ToJSON(cfg.DNSAgentCfg()) + case ATTRIBUTE_JSN: + jsonString = utils.ToJSON(cfg.AttributeSCfg()) + case ChargerSCfgJson: + jsonString = utils.ToJSON(cfg.ChargerSCfg()) + case RESOURCES_JSON: + jsonString = utils.ToJSON(cfg.ResourceSCfg()) + case STATS_JSON: + jsonString = utils.ToJSON(cfg.StatSCfg()) + case THRESHOLDS_JSON: + jsonString = utils.ToJSON(cfg.ThresholdSCfg()) + case SupplierSJson: + jsonString = utils.ToJSON(cfg.SupplierSCfg()) + case SURETAX_JSON: + jsonString = utils.ToJSON(cfg.SureTaxCfg()) + case DispatcherJson: + jsonString = utils.ToJSON(cfg.DispatcherSCfg()) + case LoaderJson: + jsonString = utils.ToJSON(cfg.LoaderCfg()) + case CgrLoaderCfgJson: + jsonString = utils.ToJSON(cfg.LoaderCgrCfg()) + case CgrMigratorCfgJson: + jsonString = utils.ToJSON(cfg.MigratorCgrCfg()) + case Apier: + jsonString = utils.ToJSON(cfg.ApierCfg()) + case CDRC_JSN: + jsonString = utils.ToJSON(cfg.CdrcProfiles) + case CDRE_JSN: + jsonString = utils.ToJSON(cfg.CdreProfiles) + default: + return errors.New("Invalid section") + } + json.Unmarshal([]byte(jsonString), reply) + return +} diff --git a/config/config_test.go b/config/config_test.go index 35c35edec..f74c240be 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -1754,3 +1754,30 @@ func TestCgrCfgJSONDefaultApierCfg(t *testing.T) { t.Errorf("received: %+v, expecting: %+v", cgrCfg.apier, aCfg) } } + +func TestCgrCfgV1GetConfigSection(t *testing.T) { + JSN_CFG := ` +{ +"listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", + } +}` + expected := map[string]interface{}{ + "HTTPListen": ":2080", + "HTTPTLSListen": "127.0.0.1:2280", + "RPCGOBListen": ":2013", + "RPCGOBTLSListen": "127.0.0.1:2023", + "RPCJSONListen": ":2012", + "RPCJSONTLSListen": "127.0.0.1:2022", + } + var rcv map[string]interface{} + if cgrCfg, err := NewCGRConfigFromJsonStringWithDefaults(JSN_CFG); err != nil { + t.Error(err) + } else if err := cgrCfg.V1GetConfigSection(&StringWithArgDispatcher{Section: LISTEN_JSN}, &rcv); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expected: %+v, received: %+v", expected, rcv) + } +} diff --git a/console/get_json_section.go b/console/get_json_section.go new file mode 100644 index 000000000..6d500efdb --- /dev/null +++ b/console/get_json_section.go @@ -0,0 +1,66 @@ +/* +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 console + +import ( + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" +) + +func init() { + c := &CmdGetJSONConfig{ + name: "get_json_section", + rpcMethod: utils.ConfigSv1GetJSONSection, + rpcParams: &config.StringWithArgDispatcher{}, + } + commands[c.Name()] = c + c.CommandExecuter = &CommandExecuter{c} +} + +// Commander implementation +type CmdGetJSONConfig struct { + name string + rpcMethod string + rpcParams *config.StringWithArgDispatcher + *CommandExecuter +} + +func (self *CmdGetJSONConfig) Name() string { + return self.name +} + +func (self *CmdGetJSONConfig) RpcMethod() string { + return self.rpcMethod +} + +func (self *CmdGetJSONConfig) RpcParams(reset bool) interface{} { + if reset || self.rpcParams == nil { + self.rpcParams = &config.StringWithArgDispatcher{} + } + return self.rpcParams +} + +func (self *CmdGetJSONConfig) PostprocessRpcParams() error { + return nil +} + +func (self *CmdGetJSONConfig) RpcResult() interface{} { + var s map[string]interface{} + return &s +} diff --git a/data/tariffplans/dispatchers/Attributes.csv b/data/tariffplans/dispatchers/Attributes.csv index 8f3d64434..0282a3f48 100644 --- a/data/tariffplans/dispatchers/Attributes.csv +++ b/data/tariffplans/dispatchers/Attributes.csv @@ -17,3 +17,4 @@ cgrates.org,ATTR_API_SCHD_AUTH,*auth,*string:~APIKey:sched12345,,,APIMethods,*co cgrates.org,ATTR_API_CDRS_AUTH,*auth,*string:~APIKey:cdrs12345,,,APIMethods,*constant,CDRsV1.Ping&CDRsV1.ProcessEvent&CDRsV1.GetCDRs&CDRsV1.CountCDRs&CDRsV1.ProcessCDR&CDRsV1.ProcessExternalCDR,false,20 cgrates.org,ATTR_API_DSP_AUTH,*auth,*string:~APIKey:dsp12345,,,APIMethods,*constant,DispatcherSv1.Ping&DispatcherSv1.GetProfileForEvent,false,20 cgrates.org,ATTR_API_PSE_AUTH,*auth,*string:~APIKey:pse12345,,,APIMethods,*constant,SessionSv1.Ping&SessionSv1.AuthorizeEvent&SessionSv1.AuthorizeEventWithDigest&SessionSv1.InitiateSession&SessionSv1.InitiateSessionWithDigest&SessionSv1.UpdateSession&SessionSv1.SyncSessions&SessionSv1.TerminateSession&SessionSv1.ProcessCDR&SessionSv1.ProcessEvent&SessionSv1.GetActiveSessions&SessionSv1.GetActiveSessionsCount&SessionSv1.ForceDisconnect&SessionSv1.GetPassiveSessions&SessionSv1.GetPassiveSessionsCount&SessionSv1.ReplicateSessions&SessionSv1.SetPassiveSession&AttributeSv1.ProcessEvent&Responder.Debit&ResourceSv1.AllocateResources&ChargerSv1.ProcessEvent&Responder.MaxDebit,false,20 +cgrates.org,ATTR_API_CFG_AUTH,*auth,*string:~APIKey:cfg12345,,,APIMethods,*constant,ConfigSv1.GetJSONSection,false,20 diff --git a/dispatchers/config.go b/dispatchers/config.go new file mode 100644 index 000000000..66d7c6115 --- /dev/null +++ b/dispatchers/config.go @@ -0,0 +1,40 @@ +/* +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 dispatchers + +import ( + "time" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" +) + +func (dS *DispatcherService) ConfigSv1GetJSONSection(args *config.StringWithArgDispatcher, reply *map[string]interface{}) (err error) { + if args.ArgDispatcher == nil { + return utils.NewErrMandatoryIeMissing("ArgDispatcher") + } + if dS.attrS != nil { + if err = dS.authorize(utils.ConfigSv1GetJSONSection, + args.Tenant, args.APIKey, utils.TimePointer(time.Now())); err != nil { + return + } + } + return dS.Dispatch(&utils.CGREvent{Tenant: args.Tenant}, + utils.MetaConfig, args.RouteID, utils.ConfigSv1GetJSONSection, args, reply) +} diff --git a/dispatchers/config_it_test.go b/dispatchers/config_it_test.go new file mode 100644 index 000000000..221c9975a --- /dev/null +++ b/dispatchers/config_it_test.go @@ -0,0 +1,63 @@ +// +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 dispatchers + +import ( + "reflect" + "testing" + + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" +) + +var sTestsDspConfig = []func(t *testing.T){ + testDspConfigSv1GetJSONSection, +} + +//Test start here +func TestDspConfigITMySQL(t *testing.T) { + testDsp(t, sTestsDspConfig, "TestDspConfigITMySQL", "all", "all2", "dispatchers", "tutorial", "oldtutorial", "dispatchers") +} + +func testDspConfigSv1GetJSONSection(t *testing.T) { + expected := map[string]interface{}{ + "HTTPListen": ":6080", + "HTTPTLSListen": "127.0.0.1:2280", + "RPCGOBListen": ":6013", + "RPCGOBTLSListen": "127.0.0.1:2023", + "RPCJSONListen": ":6012", + "RPCJSONTLSListen": "127.0.0.1:2022", + } + var reply map[string]interface{} + if err := dispEngine.RCP.Call(utils.ConfigSv1GetJSONSection, &config.StringWithArgDispatcher{ + TenantArg: utils.TenantArg{ + Tenant: "cgrates.org", + }, + ArgDispatcher: &utils.ArgDispatcher{ + APIKey: utils.StringPointer("cfg12345"), + }, + Section: "listen", + }, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(expected, reply) { + t.Errorf("Expected: %+v, received: %+v", expected, reply) + } +} diff --git a/utils/consts.go b/utils/consts.go index 7fc36cd44..f2b3f5d49 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -390,6 +390,7 @@ const ( MetaAttributes = "*attributes" MetaServiceManager = "*servicemanager" MetaChargers = "*chargers" + MetaConfig = "*config" MetaDispatchers = "*dispatchers" MetaDispatcherHosts = "*dispatcher_hosts" MetaResources = "*resources" @@ -752,6 +753,11 @@ const ( ServiceManagerV1Ping = "ServiceManagerV1.Ping" ) +const ( + ConfigSv1 = "ConfigSv1" + ConfigSv1GetJSONSection = "ConfigSv1.GetJSONSection" +) + // SupplierS APIs const ( SupplierSv1GetSuppliers = "SupplierSv1.GetSuppliers"