diff --git a/data/conf/samples/registrarc/registrarc_node_id/cgrates.json b/data/conf/samples/registrarc/registrarc_node_id/cgrates.json new file mode 100644 index 000000000..a6a5bf20e --- /dev/null +++ b/data/conf/samples/registrarc/registrarc_node_id/cgrates.json @@ -0,0 +1,85 @@ +{ + "general": { + "log_level": 7, + "reply_timeout": "30s", + "node_id":"NODE1", + }, + + "listen": { + "rpc_json": ":3012", + "rpc_gob": ":3013", + "http": ":3080", + }, + + "data_db": { // database used to store runtime data (eg: accounts, cdr stats) + "db_type": "redis", // data_db type: + "db_port": 6379, // data_db port to reach the database + "db_name": "10", // data_db database name to connect to + }, + + "stor_db": { + "db_password": "CGRateS.org", + }, + + "rpc_conns": { + "regConn": { + "strategy": "*first", + "conns": [{"address": "http://127.0.0.1:2080/registrar", "transport":"*http_jsonrpc"}] + } + }, + + "rals": { + "enabled": true, + "max_increments":3000000, + }, + + "schedulers": { + "enabled": true, + }, + + "cdrs": { + "enabled": true, + }, + + "chargers": { + "enabled": true, + "attributes_conns": ["*internal"], + }, + + + "attributes": { + "enabled": true, + "stats_conns": ["*localhost"], + "resources_conns": ["*localhost"], + "apiers_conns": ["*localhost"] + }, + + + "sessions": { + "enabled": true, + }, + + + "apiers": { + "enabled": true, + "scheduler_conns": ["*internal"], + }, + + "filters": { + "apiers_conns": ["*internal"], + }, + + "registrarc":{ + "dispatchers":{ + "enabled": true, + "registrars_conns": ["regConn"], + "hosts": [ + { + "transport": "*json", + "tls": false + }, + ], + "refresh_interval": "1s", + }, + }, + } \ No newline at end of file diff --git a/data/conf/samples/registrarc/registrars_node_id/cgrates.json b/data/conf/samples/registrarc/registrars_node_id/cgrates.json new file mode 100644 index 000000000..caa50e766 --- /dev/null +++ b/data/conf/samples/registrarc/registrars_node_id/cgrates.json @@ -0,0 +1,53 @@ +{ + "general": { + "node_id": "DispatcherS1", + "log_level": 7, + "reconnects": 1, + }, + + + "listen": { + "rpc_json": ":2012", + "rpc_gob": ":2013", + "http": ":2080", + }, + + "stor_db": { + "db_type":"*internal", + }, + + "caches":{ + "partitions": { + "*dispatcher_routes": {"limit": -1, "ttl": "2s"}, + "*dispatcher_hosts": {"limit": -1, "ttl": "2s"} + }, + }, + + "schedulers": { + "enabled": true, + }, + + "rals": { + "enabled": true, + }, + + "chargers": { + "enabled": true, + }, + + "sessions": { + "enabled": true, + "rals_conns": ["*localhost"], + "resources_conns": ["*localhost"], + "chargers_conns": ["*localhost"], + "listen_bijson": ":3014", + }, + + "dispatchers":{ + "enabled": true, + }, + + "apiers": { + "enabled": true, + "scheduler_conns": ["*internal"], + },} \ No newline at end of file diff --git a/data/tariffplans/registrarc2/DispatcherProfiles.csv b/data/tariffplans/registrarc2/DispatcherProfiles.csv new file mode 100644 index 000000000..395d38708 --- /dev/null +++ b/data/tariffplans/registrarc2/DispatcherProfiles.csv @@ -0,0 +1,2 @@ +#Tenant,ID,Subsystems,FilterIDs,ActivationInterval,Strategy,StrategyParameters,ConnID,ConnFilterIDs,ConnWeight,ConnBlocker,ConnParameters,Weight +cgrates.org,DSP,*any,,,*weight,,NODE1,,20,false,,10 \ No newline at end of file diff --git a/registrarc/libregistrarc.go b/registrarc/libregistrarc.go index c64b6e828..780731782 100644 --- a/registrarc/libregistrarc.go +++ b/registrarc/libregistrarc.go @@ -47,6 +47,11 @@ func NewRegisterArgs(cfg *config.CGRConfig, tnt string, hostCfgs []*config.Remot utils.RegistrarC, err)) return } + + if hostCfg.ID == "" { + hostCfg.ID = cfg.GeneralCfg().NodeID + } + rargs.Hosts[i] = &RegisterHostCfg{ ID: hostCfg.ID, Port: port, diff --git a/registrarc/registarc_defaultid_it_test.go b/registrarc/registarc_defaultid_it_test.go new file mode 100644 index 000000000..1a405b47d --- /dev/null +++ b/registrarc/registarc_defaultid_it_test.go @@ -0,0 +1,143 @@ +package registrarc + +import ( + "bytes" + "os/exec" + "path" + "testing" + "time" + + "github.com/cgrates/birpc/context" + + "github.com/cgrates/birpc" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +var ( + dspNodeDir string + dspNodeCfgPath string + dspNodeCfg *config.CGRConfig + dspNodeCmd *exec.Cmd + dspNodeRPC *birpc.Client + + node1Dir string + node1CfgPath string + node1Cmd *exec.Cmd + + dsphNodeTest = []func(t *testing.T){ + testDsphNodeInitCfg, + testDsphNodeInitDB, + testDsphNodeStartEngine, + testDsphNodeLoadData, + testDsphNodeBeforeDsphStart, + testDsphNodeStartAll, + testDsphNodeStopEngines, + testDsphNodeStopDispatcher, + } +) + +func TestDspNodeHosts(t *testing.T) { + switch *dbType { + case utils.MetaMySQL: + node1Dir = "registrarc_node_id" + dspNodeDir = "registrars_node_id" + case utils.MetaInternal, utils.MetaPostgres, utils.MetaMongo: + t.SkipNow() + default: + t.Fatal("Unknown Database type") + } + for _, stest := range dsphNodeTest { + t.Run(dspNodeDir, stest) + } +} + +func testDsphNodeInitCfg(t *testing.T) { + dspNodeCfgPath = path.Join(*dataDir, "conf", "samples", "registrarc", dspNodeDir) + node1CfgPath = path.Join(*dataDir, "conf", "samples", "registrarc", node1Dir) + var err error + if dspNodeCfg, err = config.NewCGRConfigFromPath(dspNodeCfgPath); err != nil { + t.Error(err) + } +} + +func testDsphNodeInitDB(t *testing.T) { + if err := engine.InitDataDb(dspNodeCfg); err != nil { + t.Fatal(err) + } + if err := engine.InitStorDb(dspNodeCfg); err != nil { + t.Fatal(err) + } +} + +func testDsphNodeStartEngine(t *testing.T) { + var err error + if dspNodeCmd, err = engine.StopStartEngine(dspNodeCfgPath, *waitRater); err != nil { + t.Fatal(err) + } + dspNodeRPC, err = newRPCClient(dspNodeCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed + if err != nil { + t.Fatal("Could not connect to rater: ", err.Error()) + } +} + +func testDsphNodeLoadData(t *testing.T) { + loader := exec.Command("cgr-loader", "-config_path", dspNodeCfgPath, "-path", path.Join(*dataDir, "tariffplans", "registrarc2"), "-caches_address=") + output := bytes.NewBuffer(nil) + outerr := bytes.NewBuffer(nil) + loader.Stdout = output + loader.Stderr = outerr + if err := loader.Run(); err != nil { + t.Log(loader.Args) + t.Log(output.String()) + t.Log(outerr.String()) + t.Fatal(err) + } +} + +func testDsphNodeGetNodeID() (id string, err error) { + var status map[string]any + if err = dspNodeRPC.Call(context.Background(), utils.DispatcherSv1RemoteStatus, utils.TenantWithAPIOpts{ + Tenant: "cgrates.org", + APIOpts: map[string]any{}, + }, &status); err != nil { + return + } + return utils.IfaceAsString(status[utils.NodeID]), nil +} + +func testDsphNodeBeforeDsphStart(t *testing.T) { + if _, err := testDsphNodeGetNodeID(); err == nil || err.Error() != utils.ErrDSPHostNotFound.Error() { + t.Errorf("Expected error: %s received: %v", utils.ErrDSPHostNotFound, err) + } +} + +func testDsphNodeStartAll(t *testing.T) { + var err error + if node1Cmd, err = engine.StartEngine(node1CfgPath, *waitRater); err != nil { + t.Fatal(err) + } + if nodeID, err := testDsphNodeGetNodeID(); err != nil { + t.Fatal(err) + } else if nodeID != "NODE1" { + t.Errorf("Expected nodeID: %q ,received: %q", "NODE1", nodeID) + } +} + +func testDsphNodeStopEngines(t *testing.T) { + if err := node1Cmd.Process.Kill(); err != nil { + t.Fatal(err) + } + + time.Sleep(2 * time.Second) + if _, err := testDsphNodeGetNodeID(); err == nil || err.Error() != utils.ErrDSPHostNotFound.Error() { + t.Errorf("Expected error: %s received: %v", utils.ErrDSPHostNotFound, err) + } +} + +func testDsphNodeStopDispatcher(t *testing.T) { + if err := engine.KillEngine(*waitRater); err != nil { + t.Error(err) + } +}