diff --git a/apier/v1/dispatcher.go b/apier/v1/dispatcher.go index 9b5ea9314..93e0f00c5 100755 --- a/apier/v1/dispatcher.go +++ b/apier/v1/dispatcher.go @@ -180,6 +180,21 @@ func (dRs *DispatcherResourceSv1) GetResourcesForEvent(args *dispatchers.ArgsV1R return dRs.dRs.ResourceSv1GetResourcesForEvent(args, reply) } +func (dRs *DispatcherResourceSv1) AuthorizeResources(args *dispatchers.ArgsV1ResUsageWithApiKey, + reply *string) error { + return dRs.dRs.ResourceSv1AuthorizeResources(args, reply) +} + +func (dRs *DispatcherResourceSv1) AllocateResources(args *dispatchers.ArgsV1ResUsageWithApiKey, + reply *string) error { + return dRs.dRs.ResourceSv1AllocateResources(args, reply) +} + +func (dRs *DispatcherResourceSv1) ReleaseResources(args *dispatchers.ArgsV1ResUsageWithApiKey, + reply *string) error { + return dRs.dRs.ResourceSv1ReleaseResources(args, reply) +} + func NewDispatcherSupplierSv1(dps *dispatchers.DispatcherService) *DispatcherSupplierSv1 { return &DispatcherSupplierSv1{dSup: dps} } diff --git a/data/tariffplans/dispatchers/Attributes.csv b/data/tariffplans/dispatchers/Attributes.csv index faa49dfcb..8a7139d17 100644 --- a/data/tariffplans/dispatchers/Attributes.csv +++ b/data/tariffplans/dispatchers/Attributes.csv @@ -6,6 +6,6 @@ cgrates.org,ATTR_API_CHRG_AUTH,*auth,*string:APIKey:chrg12345,,APIMethods,*any,C cgrates.org,ATTR_API_THR_AUTH,*auth,*string:APIKey:thr12345,,APIMethods,*any,ThresholdSv1.Ping&ThresholdSv1.GetThresholdsForEvent&ThresholdSv1.ProcessEvent&ThresholdSv1.GetThreshold&ThresholdSv1.GetThresholdIDs,true,false,20 cgrates.org,ATTR_API_SUP_AUTH,*auth,*string:APIKey:sup12345,,APIMethods,*any,SupplierSv1.Ping&SupplierSv1.GetSuppliers,true,false,20 cgrates.org,ATTR_API_STAT_AUTH,*auth,*string:APIKey:stat12345,,APIMethods,*any,StatSv1.Ping&StatSv1.GetStatQueuesForEvent&StatSv1.GetQueueStringMetrics&StatSv1.ProcessEvent&StatSv1.GetQueueIDs&StatSv1.GetQueueFloatMetrics,true,false,20 -cgrates.org,ATTR_API_RES_AUTH,*auth,*string:APIKey:res12345,,APIMethods,*any,ResourceSv1.Ping&ResourceSv1.GetResourcesForEvent,true,false,20 +cgrates.org,ATTR_API_RES_AUTH,*auth,*string:APIKey:res12345,,APIMethods,*any,ResourceSv1.Ping&ResourceSv1.GetResourcesForEvent&ResourceSv1.AuthorizeResources&ResourceSv1.AllocateResources&ResourceSv1.ReleaseResources,true,false,20 cgrates.org,ATTR_API_SES_AUTH,*auth,*string:APIKey:ses12345,,APIMethods,*any,SessionSv1.Ping&SessionSv1.AuthorizeEventWithDigest&SessionSv1.InitiateSessionWithDigest&SessionSv1.UpdateSession&SessionSv1.TerminateSession&SessionSv1.ProcessCDR&SessionSv1.ProcessEvent,true,false,20 diff --git a/dispatchers/resources.go b/dispatchers/resources.go index 276300241..30d957a83 100755 --- a/dispatchers/resources.go +++ b/dispatchers/resources.go @@ -47,5 +47,46 @@ func (dS *DispatcherService) ResourceSv1GetResourcesForEvent(args *ArgsV1ResUsag } return dS.Dispatch(&args.CGREvent, utils.MetaResources, args.RouteID, utils.ResourceSv1GetResourcesForEvent, args.ArgRSv1ResourceUsage, reply) - +} + +func (dS *DispatcherService) ResourceSv1AuthorizeResources(args *ArgsV1ResUsageWithApiKey, + reply *string) (err error) { + if dS.attrS != nil { + if err = dS.authorize(utils.ResourceSv1AuthorizeResources, + args.ArgRSv1ResourceUsage.CGREvent.Tenant, + args.APIKey, args.ArgRSv1ResourceUsage.CGREvent.Time); err != nil { + return + } + + } + return dS.Dispatch(&args.CGREvent, utils.MetaResources, args.RouteID, + utils.ResourceSv1AuthorizeResources, args.ArgRSv1ResourceUsage, reply) +} + +func (dS *DispatcherService) ResourceSv1AllocateResources(args *ArgsV1ResUsageWithApiKey, + reply *string) (err error) { + if dS.attrS != nil { + if err = dS.authorize(utils.ResourceSv1AllocateResources, + args.ArgRSv1ResourceUsage.CGREvent.Tenant, + args.APIKey, args.ArgRSv1ResourceUsage.CGREvent.Time); err != nil { + return + } + + } + return dS.Dispatch(&args.CGREvent, utils.MetaResources, args.RouteID, + utils.ResourceSv1AllocateResources, args.ArgRSv1ResourceUsage, reply) +} + +func (dS *DispatcherService) ResourceSv1ReleaseResources(args *ArgsV1ResUsageWithApiKey, + reply *string) (err error) { + if dS.attrS != nil { + if err = dS.authorize(utils.ResourceSv1ReleaseResources, + args.ArgRSv1ResourceUsage.CGREvent.Tenant, + args.APIKey, args.ArgRSv1ResourceUsage.CGREvent.Time); err != nil { + return + } + + } + return dS.Dispatch(&args.CGREvent, utils.MetaResources, args.RouteID, + utils.ResourceSv1ReleaseResources, args.ArgRSv1ResourceUsage, reply) } diff --git a/dispatchers/resources_it_test.go b/dispatchers/resources_it_test.go index dbd1b88d4..fc2f137aa 100755 --- a/dispatchers/resources_it_test.go +++ b/dispatchers/resources_it_test.go @@ -36,6 +36,7 @@ var sTestsDspRes = []func(t *testing.T){ testDspResPing, testDspResTestAuthKey, testDspResTestAuthKey2, + testDspResTestAuthKey3, } //Test start here @@ -170,3 +171,137 @@ func testDspResTestAuthKey2(t *testing.T) { t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(eRs), utils.ToJSON(rs)) } } + +func testDspResTestAuthKey3(t *testing.T) { + // first event matching Resource1 + var reply string + argsRU := ArgsV1ResUsageWithApiKey{ + DispatcherResource: DispatcherResource{ + APIKey: "res12345", + }, + ArgRSv1ResourceUsage: utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e51", + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + "Account": "1002", + "Subject": "1001", + "Destination": "1002"}, + }, + Units: 1, + }, + } + if err := dispEngine.RCP.Call(utils.ResourceSv1AllocateResources, + argsRU, &reply); err != nil { + t.Error(err) + } + eAllocationMsg := "ResGroup1" + if reply != eAllocationMsg { + t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply) + } + + if err := dispEngine.RCP.Call(utils.ResourceSv1AuthorizeResources, argsRU, &reply); err != nil { + t.Error(err) + } else if reply != eAllocationMsg { // already 3 usages active before allow call, we should have now more than allowed + t.Errorf("Expecting: %+v, received: %+v", eAllocationMsg, reply) + } + argsRU = ArgsV1ResUsageWithApiKey{ + DispatcherResource: DispatcherResource{ + APIKey: "res12345", + }, + ArgRSv1ResourceUsage: utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e61", + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + "Account": "1002", + "Subject": "1001", + "Destination": "1002"}, + }, + Units: 17, + }, + } + if err := dispEngine.RCP.Call(utils.ResourceSv1AuthorizeResources, + argsRU, &reply); err == nil || err.Error() != utils.ErrResourceUnauthorized.Error() { + t.Error(err) + } + + // relase the only resource active for Resource1 + argsRU = ArgsV1ResUsageWithApiKey{ + DispatcherResource: DispatcherResource{ + APIKey: "res12345", + }, + ArgRSv1ResourceUsage: utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e55", + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + "Account": "1002", + "Subject": "1001", + "Destination": "1002"}, + }, + }, + } + if err := dispEngine.RCP.Call(utils.ResourceSv1ReleaseResources, + argsRU, &reply); err != nil { + t.Error(err) + } + // try reserving with full units for Resource1, case which did not work in previous test + // only match Resource1 since we don't want for storing of the resource2 bellow + argsRU = ArgsV1ResUsageWithApiKey{ + DispatcherResource: DispatcherResource{ + APIKey: "res12345", + }, + ArgRSv1ResourceUsage: utils.ArgRSv1ResourceUsage{ + UsageID: "651a8db2-4f67-4cf8-b622-169e8a482e61", + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + Event: map[string]interface{}{ + "Account": "1002", + "Subject": "1001", + "Destination": "1002"}, + }, + Units: 7, + }, + } + if err := dispEngine.RCP.Call(utils.ResourceSv1AuthorizeResources, argsRU, &reply); err != nil { + t.Error(err) + } else if reply != "ResGroup1" { + t.Error("Unexpected reply returned", reply) + } + var rs *engine.Resources + args := &ArgsV1ResUsageWithApiKey{ + DispatcherResource: DispatcherResource{ + APIKey: "res12345", + }, + ArgRSv1ResourceUsage: utils.ArgRSv1ResourceUsage{ + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + ID: "Event5", + Event: map[string]interface{}{ + "Account": "1002", + "Subject": "1001", + "Destination": "1002"}, + }, + }, + } + if err := dispEngine.RCP.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil { + t.Error(err) + } else if len(*rs) != 1 { + t.Errorf("Resources: %+v", utils.ToJSON(rs)) + } + if rs == nil { + t.Errorf("Expecting rs to not be nil") + // rs shoud not be nil so exit function + // to avoid nil segmentation fault; + // if this happens try to run this test manualy + return + } + // make sure Resource1 have no more active resources + for _, r := range *rs { + if r.ID == "ResGroup1" && + (len(r.Usages) != 0 || len(r.TTLIdx) != 0) { + t.Errorf("Unexpected resource: %+v", r) + } + } +} diff --git a/dispatchers/stats_it_test.go b/dispatchers/stats_it_test.go index 5a8e47457..bac185490 100755 --- a/dispatchers/stats_it_test.go +++ b/dispatchers/stats_it_test.go @@ -335,4 +335,29 @@ func testDspStsTestAuthKey3(t *testing.T) { t.Errorf("expecting: %+v, received reply: %v", estats, reply) } + estats = []string{"Stats2"} + if err := dispEngine.RCP.Call(utils.StatSv1GetStatQueuesForEvent, + &ArgsStatProcessEventWithApiKey{ + StatsArgsProcessEvent: engine.StatsArgsProcessEvent{ + CGREvent: utils.CGREvent{ + Tenant: "cgrates.org", + ID: "GetStats", + Event: map[string]interface{}{ + utils.Account: "1002", + utils.AnswerTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC), + utils.Usage: time.Duration(45 * time.Second), + utils.RunID: utils.DEFAULT_RUNID, + utils.COST: 10.0, + utils.Destination: "1001", + }, + }, + }, + DispatcherResource: DispatcherResource{ + APIKey: "stat12345", + }, + }, &reply); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(estats, reply) { + t.Errorf("expecting: %+v, received reply: %v", estats, reply) + } }