From 5565d87d6b2602bb6017d792033bc6ec892857c4 Mon Sep 17 00:00:00 2001 From: porosnicuadrian Date: Thu, 1 Jul 2021 16:57:54 +0300 Subject: [PATCH] Addec all cores APIs in dispatchers + tests --- data/tariffplans/dispatchers/Attributes.csv | 2 +- dispatchers/core.go | 72 ++++++++++ dispatchers/core_it_test.go | 142 ++++++++++++++++++++ utils/coreutils.go | 8 ++ 4 files changed, 223 insertions(+), 1 deletion(-) diff --git a/data/tariffplans/dispatchers/Attributes.csv b/data/tariffplans/dispatchers/Attributes.csv index 3c92034d1..4d924c2fe 100644 --- a/data/tariffplans/dispatchers/Attributes.csv +++ b/data/tariffplans/dispatchers/Attributes.csv @@ -23,6 +23,6 @@ cgrates.org,ATTR_API_RALS_AUTH,*auth,*string:~*req.ApiKey:rals12345,,,*req.APIMe cgrates.org,ATTR_API_REPLICATOR_AUTH,*auth,*string:~*req.ApiKey:repl12345,,,*req.APIMethods,*constant,ReplicatorSv1.Ping&ReplicatorSv1.GetAccount&ReplicatorSv1.SetAccount&ReplicatorSv1.RemoveAccount&ReplicatorSv1.GetRouteProfile&ReplicatorSv1.SetRouteProfile&ReplicatorSv1.RemoveRouteProfile&ReplicatorSv1.GetAttributeProfile&ReplicatorSv1.SetAttributeProfile&ReplicatorSv1.RemoveAttributeProfile&ReplicatorSv1.SetChargerProfile&ReplicatorSv1.GetChargerProfile&ReplicatorSv1.RemoveChargerProfile&ReplicatorSv1.GetDispatcherProfile&ReplicatorSv1.SetDispatcherProfile&ReplicatorSv1.RemoveDispatcherProfile&ReplicatorSv1.GetDispatcherHost&ReplicatorSv1.SetDispatcherHost&ReplicatorSv1.RemoveDispatcherHost&ReplicatorSv1.GetFilter&ReplicatorSv1.SetFilter&ReplicatorSv1.RemoveFilter&ReplicatorSv1.GetThreshold&ReplicatorSv1.SetThreshold&ReplicatorSv1.RemoveThreshold&ReplicatorSv1.GetStatQueue&ReplicatorSv1.SetStatQueue&ReplicatorSv1.RemoveStatQueue&ReplicatorSv1.GetResource&ReplicatorSv1.SetResource&ReplicatorSv1.RemoveResource&ReplicatorSv1.GetResourceProfile&ReplicatorSv1.SetResourceProfile&ReplicatorSv1.RemoveResourceProfile&ReplicatorSv1.GetStatQueueProfile&ReplicatorSv1.SetStatQueueProfile&ReplicatorSv1.RemoveStatQueueProfile&ReplicatorSv1.GetThresholdProfile&ReplicatorSv1.SetThresholdProfile&ReplicatorSv1.RemoveThresholdProfile&ReplicatorSv1.GetTiming&ReplicatorSv1.SetTiming&ReplicatorSv1.RemoveTiming&ReplicatorSv1.GetActionTriggers&ReplicatorSv1.SetActionTriggers&ReplicatorSv1.RemoveActionTriggers&ReplicatorSv1.SetSharedGroup&ReplicatorSv1.GetSharedGroup&ReplicatorSv1.RemoveSharedGroup&ReplicatorSv1.SetActions&ReplicatorSv1.GetActions&ReplicatorSv1.RemoveActions&ReplicatorSv1.SetActionPlan&ReplicatorSv1.GetActionPlan&ReplicatorSv1.RemoveActionPlan&ReplicatorSv1.SetAccountActionPlans&ReplicatorSv1.GetAccountActionPlans&ReplicatorSv1.RemAccountActionPlans&ReplicatorSv1.SetRatingPlan&ReplicatorSv1.GetRatingPlan&ReplicatorSv1.RemoveRatingPlan&ReplicatorSv1.SetRatingProfile&ReplicatorSv1.GetRatingProfile&ReplicatorSv1.RemoveRatingProfile&ReplicatorSv1.SetDestination&ReplicatorSv1.GetDestination&ReplicatorSv1.RemoveDestination&ReplicatorSv1.SetLoadIDs&ReplicatorSv1.GetItemLoadIDs,false,20 cgrates.org,ATTR_API_CDRSV2,*auth,*string:~*req.ApiKey:cdrsv212345,,,*req.APIMethods,*constant,CDRsV2.ProcessEvent&CDRsV2.StoreSessionCost,false,20 cgrates.org,ATTR_API_RATES_AUTH,*auth,*string:~*req.ApiKey:rPrf12345,,,*req.APIMethods,*constant,RateSv1.Ping&RateSv1.CostForEvent,false,20 -cgrates.org,ATTR_API_CORE_AUTH,*auth,*string:~*req.ApiKey:core12345,,,*req.APIMethods,*constant,CoreSv1.Status&CoreSv1.Ping&CoreSv1.Sleep,false,20 +cgrates.org,ATTR_API_CORE_AUTH,*auth,*string:~*req.ApiKey:core12345,,,*req.APIMethods,*constant,CoreSv1.Status&CoreSv1.Ping&CoreSv1.Sleep&CoreSv1.StartCPUProfiling&CoreSv1.StopCPUProfiling&CoreSv1.StartMemoryProfiling&CoreSv1.StopMemoryProfiling,false,20 cgrates.org,ATTR_API_ACTIONS_AUTH,*auth,*string:~*req.ApiKey:actPrf12345,,,*req.APIMethods,*constant,ActionSv1.Ping,false,20 cgrates.org,ATTR_API_ACCOUNTS_AUTH,*auth,*string:~*req.ApiKey:accPrf12345,,,*req.APIMethods,*constant,AccountSv1.Ping,false,20 \ No newline at end of file diff --git a/dispatchers/core.go b/dispatchers/core.go index 3d9651f82..5c52bdf84 100644 --- a/dispatchers/core.go +++ b/dispatchers/core.go @@ -73,3 +73,75 @@ func (dS *DispatcherService) CoreSv1Sleep(args *utils.DurationArgs, APIOpts: args.APIOpts, }, utils.MetaCore, utils.CoreSv1Sleep, args, reply) } + +func (dS *DispatcherService) CoreSv1StartCPUProfiling(args *utils.DirectoryArgs, + reply *string) (err error) { + tnt := dS.cfg.GeneralCfg().DefaultTenant + if args.Tenant != utils.EmptyString { + tnt = args.Tenant + } + if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { + if err = dS.authorize(utils.CoreSv1StartCPUProfiling, tnt, + utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { + return + } + } + return dS.Dispatch(&utils.CGREvent{ + Tenant: tnt, + APIOpts: args.APIOpts, + }, utils.MetaCore, utils.CoreSv1StartCPUProfiling, args, reply) +} + +func (dS *DispatcherService) CoreSv1StopCPUProfiling(args *utils.DirectoryArgs, + reply *string) (err error) { + tnt := dS.cfg.GeneralCfg().DefaultTenant + if args.Tenant != utils.EmptyString { + tnt = args.Tenant + } + if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { + if err = dS.authorize(utils.CoreSv1StopCPUProfiling, tnt, + utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { + return + } + } + return dS.Dispatch(&utils.CGREvent{ + Tenant: tnt, + APIOpts: args.APIOpts, + }, utils.MetaCore, utils.CoreSv1StopCPUProfiling, args, reply) +} + +func (dS *DispatcherService) CoreSv1StartMemoryProfiling(args *utils.MemoryPrf, + reply *string) (err error) { + tnt := dS.cfg.GeneralCfg().DefaultTenant + if args.Tenant != utils.EmptyString { + tnt = args.Tenant + } + if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { + if err = dS.authorize(utils.CoreSv1StartMemoryProfiling, tnt, + utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { + return + } + } + return dS.Dispatch(&utils.CGREvent{ + Tenant: tnt, + APIOpts: args.APIOpts, + }, utils.MetaCore, utils.CoreSv1StartMemoryProfiling, args, reply) +} + +func (dS *DispatcherService) CoreSv1StopMemoryProfiling(args *utils.MemoryPrf, + reply *string) (err error) { + tnt := dS.cfg.GeneralCfg().DefaultTenant + if args.Tenant != utils.EmptyString { + tnt = args.Tenant + } + if len(dS.cfg.DispatcherSCfg().AttributeSConns) != 0 { + if err = dS.authorize(utils.CoreSv1StopMemoryProfiling, tnt, + utils.IfaceAsString(args.APIOpts[utils.OptsAPIKey]), utils.TimePointer(time.Now())); err != nil { + return + } + } + return dS.Dispatch(&utils.CGREvent{ + Tenant: tnt, + APIOpts: args.APIOpts, + }, utils.MetaCore, utils.CoreSv1StopMemoryProfiling, args, reply) +} diff --git a/dispatchers/core_it_test.go b/dispatchers/core_it_test.go index a99c283bc..e32c51c72 100644 --- a/dispatchers/core_it_test.go +++ b/dispatchers/core_it_test.go @@ -21,7 +21,10 @@ along with this program. If not, see package dispatchers import ( + "fmt" "net/rpc" + "os" + "path" "testing" "time" @@ -30,6 +33,8 @@ import ( var sTestsDspCore = []func(t *testing.T){ testDspCoreLoad, + testDspCoreCPUProfile, + testDspCoreMemoryProfile, } //Test start here @@ -103,5 +108,142 @@ func testDspCoreLoad(t *testing.T) { } else if rply != utils.OK { t.Errorf("Expected: %q ,received: %q", utils.OK, rply) } +} + +func testDspCoreCPUProfile(t *testing.T) { + var reply string + args := &utils.DirectoryArgs{ + DirPath: "/tmp", + } + //apikey is missing + expectedErr := "MANDATORY_IE_MISSING: [ApiKey]" + if err := dispEngine.RPC.Call(utils.CoreSv1StartCPUProfiling, + args, &reply); err == nil || err.Error() != expectedErr { + t.Errorf("Expected %+v, received %+v", expectedErr, err) + } + + args = &utils.DirectoryArgs{ + DirPath: "/tmp", + APIOpts: map[string]interface{}{ + utils.OptsAPIKey: "core12345", + }, + } + if err := dispEngine.RPC.Call(utils.CoreSv1StartCPUProfiling, + args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned") + } + + args = &utils.DirectoryArgs{ + APIOpts: map[string]interface{}{ + utils.OptsAPIKey: "core12345", + }, + } + if err := dispEngine.RPC.Call(utils.CoreSv1StopCPUProfiling, + args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned") + } + file, err := os.Open(path.Join("/tmp", utils.CpuPathCgr)) + if err != nil { + t.Error(err) + } + defer file.Close() + + //compare the size + size, err := file.Stat() + if err != nil { + t.Error(err) + } else if size.Size() < int64(415) { + t.Errorf("Size of CPUProfile %v is lower that expected", size.Size()) + } + //after we checked that CPUProfile was made successfully, can delete it + if err := os.Remove(path.Join("/tmp", utils.CpuPathCgr)); err != nil { + t.Error(err) + } +} + +func testDspCoreMemoryProfile(t *testing.T) { + var reply string + args := &utils.MemoryPrf{ + DirPath: "/tmp", + Interval: 100 * time.Millisecond, + NrFiles: 2, + } + //missing apiKey + expectedErr := "MANDATORY_IE_MISSING: [ApiKey]" + if err := dispEngine.RPC.Call(utils.CoreSv1StartMemoryProfiling, + args, &reply); err == nil || err.Error() != expectedErr { + t.Errorf("Expected %+v, received %+v", expectedErr, err) + } + args = &utils.MemoryPrf{ + DirPath: "/tmp", + Interval: 100 * time.Millisecond, + NrFiles: 2, + APIOpts: map[string]interface{}{ + utils.OptsAPIKey: "core12345", + }, + } + if err := dispEngine.RPC.Call(utils.CoreSv1StartMemoryProfiling, + args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned") + } + + dur := &utils.DurationArgs{ + Duration: 500 * time.Millisecond, + Tenant: "cgrates.org", + APIOpts: map[string]interface{}{ + utils.OptsAPIKey: "core12345", + utils.OptsRouteID: "core1", + "EventType": "LoadDispatcher", + }, + } + + if err := dispEngine.RPC.Call(utils.CoreSv1Sleep, + dur, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned") + } + + args = &utils.MemoryPrf{ + DirPath: "/tmp", + Interval: 100 * time.Millisecond, + NrFiles: 2, + APIOpts: map[string]interface{}{ + utils.OptsAPIKey: "core12345", + }, + } + if err := dispEngine.RPC.Call(utils.CoreSv1StopMemoryProfiling, + args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Errorf("Unexpected reply returned") + } + + //mem_prof1, mem_prof2 + for i := 1; i <= 2; i++ { + file, err := os.Open(path.Join("/tmp", fmt.Sprintf("mem%v.prof", i))) + if err != nil { + t.Error(err) + } + defer file.Close() + + //compare the size + size, err := file.Stat() + if err != nil { + t.Error(err) + } else if size.Size() < int64(415) { + t.Errorf("Size of MemoryProfile %v is lower that expected", size.Size()) + } + //after we checked that CPUProfile was made successfully, can delete it + if err := os.Remove(path.Join("/tmp", fmt.Sprintf("mem%v.prof", i))); err != nil { + t.Error(err) + } + } } diff --git a/utils/coreutils.go b/utils/coreutils.go index c2e3cf330..2dc6c11e8 100644 --- a/utils/coreutils.go +++ b/utils/coreutils.go @@ -742,9 +742,11 @@ type TenantWithAPIOpts struct { } type MemoryPrf struct { + Tenant string DirPath string Interval time.Duration NrFiles int + APIOpts map[string]interface{} } type TenantID struct { @@ -972,6 +974,12 @@ type DurationArgs struct { Tenant string } +type DirectoryArgs struct { + DirPath string + APIOpts map[string]interface{} + Tenant string +} + // AESEncrypt will encrypt the provided txt using the encKey and AES algorithm func AESEncrypt(txt, encKey string) (encrypted string, err error) { key, _ := hex.DecodeString(encKey)