From 727f90fc6b60f6617cb2603c99380e03502aaf77 Mon Sep 17 00:00:00 2001 From: arberkatellari Date: Mon, 4 Mar 2024 17:47:25 +0200 Subject: [PATCH] Add CAPs counting to cgr-console status command --- config/config_defaults.go | 4 +- cores/core.go | 8 ++ cores/core_it_test.go | 120 +++++++++++++++++++++++ cores/core_test.go | 3 +- data/conf/samples/caps_peak/cgrates.json | 21 ++++ utils/consts.go | 2 + 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 cores/core_it_test.go create mode 100644 data/conf/samples/caps_peak/cgrates.json diff --git a/config/config_defaults.go b/config/config_defaults.go index d27e6edf1..67c1ea1dd 100644 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -79,8 +79,8 @@ const CGRATES_CFG_JSON = ` "cores": { "caps": 0, // maximum concurrent request allowed ( 0 to disabled ) - "caps_strategy": "*busy", // strategy in case in case of concurrent requests reached - "caps_stats_interval": "0", // the interval we sample for caps stats ( 0 to disabled ) + "caps_strategy": "*busy", // strategy in case of concurrent requests reached + "caps_stats_interval": "0", // the interval duration we sample for caps stats ( 0 to disabled ) "ees_conns": [], // connections to EventExporter "shutdown_timeout": "1s" // the duration to wait until all services are stopped }, diff --git a/cores/core.go b/cores/core.go index a19a70482..a8a5ef78c 100644 --- a/cores/core.go +++ b/cores/core.go @@ -49,6 +49,7 @@ func NewCoreService(cfg *config.CGRConfig, caps *engine.Caps, fileCPU io.Closer, CapsStats: st, fileCPU: fileCPU, fileMEM: fileMem, + caps: caps, } } @@ -61,6 +62,7 @@ type CoreS struct { fileCPU io.Closer fileMx sync.Mutex shtDw context.CancelFunc + caps *engine.Caps } func (cS *CoreS) ShutdownEngine() { @@ -149,6 +151,12 @@ func (cS *CoreS) V1Status(_ *context.Context, _ *utils.TenantWithAPIOpts, reply } response[utils.RunningSince] = utils.GetStartTime() response[utils.GoVersion] = runtime.Version() + if cS.cfg.CoreSCfg().Caps != 0 { + response[utils.CAPSAllocated] = cS.caps.Allocated() + if cS.cfg.CoreSCfg().CapsStatsInterval != 0 { + response[utils.CAPSPeak] = cS.CapsStats.GetPeak() + } + } *reply = response return } diff --git a/cores/core_it_test.go b/cores/core_it_test.go new file mode 100644 index 000000000..8eb7ab901 --- /dev/null +++ b/cores/core_it_test.go @@ -0,0 +1,120 @@ +//go:build integration +// +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 cores + +import ( + "net/rpc/jsonrpc" + "path" + "testing" + "time" + + "github.com/cgrates/birpc/context" + "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +func TestCAPsStatusAllocated(t *testing.T) { + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + cfgPath := path.Join("/usr/share/cgrates", "conf", "samples", "caps_queue") + cfg, err := config.NewCGRConfigFromPath(ctx, cfgPath) + if err != nil { + t.Error(err) + } + + if _, err := engine.StopStartEngine(cfgPath, 100); err != nil { + t.Fatal(err) + } + defer engine.KillEngine(100) + + client, err := jsonrpc.Dial(utils.TCP, cfg.ListenCfg().RPCJSONListen) + if err != nil { + t.Fatalf("could not establish connection to engine: %v", err) + } + + cfgStr := `{"cores":{"caps":2,"caps_stats_interval":"0","caps_strategy":"*queue","ees_conns":[],"shutdown_timeout":"1s"}}` + + var rpl string + if err := client.Call(utils.ConfigSv1GetConfigAsJSON, &config.SectionWithAPIOpts{ + Tenant: "cgrates.org", + Sections: []string{config.CoreSJSON}, + }, &rpl); err != nil { + t.Error(err) + } else if cfgStr != rpl { + t.Errorf("Expected %q , \nreceived: %q", cfgStr, rpl) + } + + var reply map[string]any + if err := client.Call(utils.CoreSv1Status, utils.TenantWithAPIOpts{}, + &reply); err != nil { + t.Fatal(err) + } else if reply[utils.NodeID] != "ConcurrentQueueEngine" { + t.Errorf("Expected %+v , received: %+v ", "ConcurrentQueueEngine", reply) + } else if _, has := reply[utils.CAPSAllocated]; !has { + t.Errorf("Expected reply to contain CAPSAllocated , received <%+v>", reply) + } + +} +func TestCAPsStatusPeak(t *testing.T) { + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + cfgPath := path.Join("/usr/share/cgrates", "conf", "samples", "caps_peak") + cfg, err := config.NewCGRConfigFromPath(ctx, cfgPath) + if err != nil { + t.Error(err) + } + if _, err := engine.StopStartEngine(cfgPath, 100); err != nil { + t.Fatal(err) + } + defer engine.KillEngine(100) + + client, err := jsonrpc.Dial(utils.TCP, cfg.ListenCfg().RPCJSONListen) + if err != nil { + t.Fatalf("could not establish connection to engine: %v", err) + } + cfgStr := `{"cores":{"caps":2,"caps_stats_interval":"100ms","caps_strategy":"*queue","ees_conns":[],"shutdown_timeout":"1s"}}` + + var rpl string + if err := client.Call(utils.ConfigSv1GetConfigAsJSON, &config.SectionWithAPIOpts{ + Tenant: "cgrates.org", + Sections: []string{config.CoreSJSON}, + }, &rpl); err != nil { + t.Error(err) + } else if cfgStr != rpl { + t.Errorf("Expected %q , \nreceived: %q", cfgStr, rpl) + } + + var reply map[string]any + if err := client.Call(utils.CoreSv1Status, utils.TenantWithAPIOpts{}, + &reply); err != nil { + t.Fatal(err) + } else if reply[utils.NodeID] != "CAPSPeakEngine" { + t.Errorf("Expected %+v , received: %+v ", "CAPSPeakEngine", reply) + } else if _, has := reply[utils.CAPSPeak]; !has { + t.Errorf("Expected reply to contain CAPSPeak , received <%+v>", reply) + } + +} diff --git a/cores/core_test.go b/cores/core_test.go index 89f433217..18d6a11cf 100644 --- a/cores/core_test.go +++ b/cores/core_test.go @@ -41,6 +41,7 @@ func TestNewCoreService(t *testing.T) { cfg: cfgDflt, CapsStats: sts, fileMEM: "/tmp", + caps: caps, } rcv := NewCoreService(cfgDflt, caps, nil, "/tmp", stopMemChan, stopchan, nil, nil) if !reflect.DeepEqual(expected, rcv) { @@ -95,7 +96,7 @@ func TestCoreServiceStatus(t *testing.T) { } utils.GitCommitDate = "wrong format" utils.GitCommitHash = "73014DAA0C1D7EDCB532D5FE600B8A20D588CDF8" - if err := cores.V1Status(context.Background(), args, &reply); err != nil { + if err := cores.V1Status(nil, nil, &reply); err != nil { t.Error(err) } diff --git a/data/conf/samples/caps_peak/cgrates.json b/data/conf/samples/caps_peak/cgrates.json new file mode 100644 index 000000000..762299394 --- /dev/null +++ b/data/conf/samples/caps_peak/cgrates.json @@ -0,0 +1,21 @@ +{ + + "general": { + "node_id": "CAPSPeakEngine" + }, + + "logger": { + "level": 7 + }, + + "cores": { + "caps": 2, + "caps_strategy": "*queue", + "caps_stats_interval": "100ms" + }, + + "admins": { + "enabled": true + } + +} \ No newline at end of file diff --git a/utils/consts.go b/utils/consts.go index 88e8d0827..45f98415d 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -329,6 +329,8 @@ const ( MemoryUsage = "MemoryUsage" RunningSince = "RunningSince" GoVersion = "GoVersion" + CAPSAllocated = "CAPSAllocated" + CAPSPeak = "CAPSPeak" // XML = "xml" MetaGOB = "*gob"