diff --git a/apis/filter_indexes_it_test.go b/apis/filter_indexes_it_test.go index 84557b9c4..414609ad7 100644 --- a/apis/filter_indexes_it_test.go +++ b/apis/filter_indexes_it_test.go @@ -3592,26 +3592,26 @@ func testV1FIdxSetRouteSProfileWithFltr(t *testing.T) { } //we will set a RouteProfile with our filter and check the indexes - rtPrf := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{ + rtPrf := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ Tenant: "cgrates.org", ID: "ROUTE_1", FilterIDs: []string{"fltr_for_attr", "*string:~*req.Account:1001"}, Sorting: utils.MetaWeight, - Routes: []*engine.Route{ + Routes: []*engine.ExternalRoute{ { ID: "local", RateProfileIDs: []string{"RP_LOCAL"}, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, { ID: "mobile", RateProfileIDs: []string{"RP_MOBILE"}, - Weights: utils.DynamicWeights{{Weight: 30}}, + Weights: ";30", }, }, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, } if err := tFIdxRpc.Call(context.Background(), utils.AdminSv1SetRouteProfile, @@ -3690,27 +3690,27 @@ func testV1FIdxSetRouteSMoreFltrsMoreIndexing(t *testing.T) { t.Error("Unexpected reply result", reply) } // update our RoutesProfile with our filters - rtPrf := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{ + rtPrf := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ Tenant: "cgrates.org", ID: "ROUTE_1", FilterIDs: []string{"fltr_for_attr", "fltr_for_attr2", "fltr_for_attr3", "*string:~*req.Account:1001"}, Sorting: utils.MetaWeight, - Routes: []*engine.Route{ + Routes: []*engine.ExternalRoute{ { ID: "local", RateProfileIDs: []string{"RP_LOCAL"}, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, { ID: "mobile", RateProfileIDs: []string{"RP_MOBILE"}, - Weights: utils.DynamicWeights{{Weight: 30}}, + Weights: ";30", }, }, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, } if err := tFIdxRpc.Call(context.Background(), utils.AdminSv1SetRouteProfile, @@ -3800,38 +3800,38 @@ func testV1FIdxRouteSProfileComputeIndexes(t *testing.T) { func testV1FIdxRouteSMoreProfilesForFltrs(t *testing.T) { // will add more routes with our filters for matching indexes - rtPrf1 := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{ + rtPrf1 := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ Tenant: "cgrates.org", ID: "ROUTE_2", FilterIDs: []string{"fltr_for_attr2", "fltr_for_attr3", "*string:~*req.Account:1001"}, Sorting: utils.MetaWeight, - Routes: []*engine.Route{ + Routes: []*engine.ExternalRoute{ { ID: "route1", RateProfileIDs: []string{"RP_LOCAL"}, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, }, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, } - rtPrf2 := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{ + rtPrf2 := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ Tenant: "cgrates.org", ID: "ROUTE_3", FilterIDs: []string{"fltr_for_attr", "*string:~*req.Account:1001"}, Sorting: utils.MetaWeight, - Routes: []*engine.Route{ + Routes: []*engine.ExternalRoute{ { ID: "route2", RateProfileIDs: []string{"RP_LOCAL"}, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, }, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, } var reply string diff --git a/apis/loaders_it_test.go b/apis/loaders_it_test.go index ab02f52ce..6190ba5a3 100644 --- a/apis/loaders_it_test.go +++ b/apis/loaders_it_test.go @@ -799,22 +799,22 @@ func testLoadersGetRouteProfile(t *testing.T) { t.Errorf("expected: <%+v>, \nreceived: <%+v>", expIDs, rtIDs) } - expRtPrf := engine.RouteProfile{ + expRtPrf := engine.APIRouteProfile{ Tenant: "cgrates.org", ID: "ROUTE_ACNT_1001", FilterIDs: []string{"FLTR_ACCOUNT_1001"}, Sorting: utils.MetaWeight, SortingParameters: []string{}, - Routes: []*engine.Route{ + Routes: []*engine.ExternalRoute{ { ID: "route1", - Weights: utils.DynamicWeights{{Weight: 20}}, + Weights: ";20", }, }, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", } - var rplyRtPrf engine.RouteProfile + var rplyRtPrf engine.APIRouteProfile if err := ldrRPC.Call(context.Background(), utils.AdminSv1GetRouteProfile, utils.TenantID{ Tenant: "cgrates.org", @@ -1116,7 +1116,7 @@ func testLoadersGetRouteProfileAfterRemove(t *testing.T) { t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ErrNotFound, err) } - var rplyRtPrf engine.RouteProfile + var rplyRtPrf engine.APIRouteProfile if err := ldrRPC.Call(context.Background(), utils.AdminSv1GetRouteProfile, utils.TenantID{ Tenant: "cgrates.org", diff --git a/apis/routes.go b/apis/routes.go index d8d730dcf..13d7e6165 100644 --- a/apis/routes.go +++ b/apis/routes.go @@ -24,7 +24,7 @@ import ( ) // GetRouteProfile returns a Route configuration -func (adms *AdminSv1) GetRouteProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.RouteProfile) error { +func (adms *AdminSv1) GetRouteProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.APIRouteProfile) error { if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing return utils.NewErrMandatoryIeMissing(missing...) } @@ -35,7 +35,7 @@ func (adms *AdminSv1) GetRouteProfile(ctx *context.Context, arg *utils.TenantIDW if rp, err := adms.dm.GetRouteProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional); err != nil { return utils.APIErrorHandler(err) } else { - *reply = *rp + *reply = *engine.NewAPIRouteProfile(rp) } return nil } @@ -81,20 +81,19 @@ func (adms *AdminSv1) GetRouteProfileCount(ctx *context.Context, args *utils.Ten return nil } -type RouteWithAPIOpts struct { - *engine.RouteProfile - APIOpts map[string]interface{} -} - //SetRouteProfile add a new Route configuration -func (adms *AdminSv1) SetRouteProfile(ctx *context.Context, args *RouteWithAPIOpts, reply *string) error { - if missing := utils.MissingStructFields(args.RouteProfile, []string{utils.ID}); len(missing) != 0 { +func (adms *AdminSv1) SetRouteProfile(ctx *context.Context, args *engine.APIRouteProfileWithAPIOpts, reply *string) error { + if missing := utils.MissingStructFields(args.APIRouteProfile, []string{utils.ID}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } if args.Tenant == utils.EmptyString { args.Tenant = adms.cfg.GeneralCfg().DefaultTenant } - if err := adms.dm.SetRouteProfile(ctx, args.RouteProfile, true); err != nil { + rp, err := args.AsRouteProfile() + if err != nil { + return err + } + if err := adms.dm.SetRouteProfile(ctx, rp, true); err != nil { return utils.APIErrorHandler(err) } //generate a loadID for CacheRouteProfiles and store it in database @@ -103,7 +102,7 @@ func (adms *AdminSv1) SetRouteProfile(ctx *context.Context, args *RouteWithAPIOp } //handle caching for SupplierProfile if err := adms.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.CacheOpt]), args.Tenant, utils.CacheRouteProfiles, - args.TenantID(), &args.FilterIDs, args.APIOpts); err != nil { + rp.TenantID(), &args.FilterIDs, args.APIOpts); err != nil { return utils.APIErrorHandler(err) } *reply = utils.OK diff --git a/apis/routes_test.go b/apis/routes_test.go index 85c707c56..7f9178e5b 100644 --- a/apis/routes_test.go +++ b/apis/routes_test.go @@ -43,15 +43,16 @@ func TestRoutesSetGetRemRouteProfile(t *testing.T) { ID: "routeID", }, } - var result engine.RouteProfile + var result engine.APIRouteProfile var reply string - rtPrf := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{ + rtPrf := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ Tenant: "cgrates.org", ID: "routeID", FilterIDs: []string{"*string:~*req.Account:1001"}, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", + Routes: []*engine.ExternalRoute{{}}, }, } @@ -63,9 +64,9 @@ func TestRoutesSetGetRemRouteProfile(t *testing.T) { if err := adms.GetRouteProfile(context.Background(), arg, &result); err != nil { t.Error(err) - } else if !reflect.DeepEqual(result, *rtPrf.RouteProfile) { + } else if !reflect.DeepEqual(result, *rtPrf.APIRouteProfile) { t.Errorf("\nexpected: <%+v>, \nreceived: <%+v>", - utils.ToJSON(rtPrf.RouteProfile), utils.ToJSON(result)) + utils.ToJSON(rtPrf.APIRouteProfile), utils.ToJSON(result)) } var rtPrfIDs []string @@ -112,7 +113,7 @@ func TestRoutesGetRouteProfileCheckErrors(t *testing.T) { cfg: cfg, dm: dm, } - var rcv engine.RouteProfile + var rcv engine.APIRouteProfile experr := "MANDATORY_IE_MISSING: [ID]" if err := adms.GetRouteProfile(context.Background(), &utils.TenantIDWithAPIOpts{ @@ -145,8 +146,10 @@ func TestRoutesSetRouteProfileCheckErrors(t *testing.T) { dm: dm, } - rtPrf := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{}, + rtPrf := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ + Routes: []*engine.ExternalRoute{{}}, + }, } var reply string @@ -219,11 +222,12 @@ func TestRoutesRemoveRouteProfileCheckErrors(t *testing.T) { dm: dm, } - rtPrf := &RouteWithAPIOpts{ - RouteProfile: &engine.RouteProfile{ + rtPrf := &engine.APIRouteProfileWithAPIOpts{ + APIRouteProfile: &engine.APIRouteProfile{ ID: "TestRoutesRemoveRouteProfileCheckErrors", Tenant: "cgrates.org", - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", + Routes: []*engine.ExternalRoute{{}}, }, } var reply string @@ -249,7 +253,7 @@ func TestRoutesRemoveRouteProfileCheckErrors(t *testing.T) { cancel() adms.cfg.GeneralCfg().DefaultCaching = utils.MetaNone - var rcv engine.RouteProfile + var rcv engine.APIRouteProfile if err := adms.GetRouteProfile(context.Background(), &utils.TenantIDWithAPIOpts{ TenantID: &utils.TenantID{ diff --git a/cmd/cgr-loader/cgr-loader_remove_it_test.go b/cmd/cgr-loader/cgr-loader_remove_it_test.go index 66ed64034..8398bba34 100644 --- a/cmd/cgr-loader/cgr-loader_remove_it_test.go +++ b/cmd/cgr-loader/cgr-loader_remove_it_test.go @@ -180,7 +180,7 @@ func testCgrLdrGetSubsystemsNotLoadedLoad(t *testing.T) { } // routesPrf - var replyRts *engine.RouteProfile + var replyRts *engine.APIRouteProfile if err := cgrLdrBIRPC.Call(context.Background(), utils.AdminSv1GetRouteProfile, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "ROUTE_ACNT_1001"}}, &replyRts); err == nil || err.Error() != utils.ErrNotFound.Error() { @@ -534,25 +534,25 @@ func testCgrLdrGetResourceAfterLoad(t *testing.T) { } func testCgrLdrGetRouteProfileAfterLoad(t *testing.T) { - expRoutePrf := &engine.RouteProfile{ + expRoutePrf := &engine.APIRouteProfile{ ID: "ROUTE_ACNT_1001", Tenant: "cgrates.org", FilterIDs: []string{"FLTR_ACCOUNT_1001"}, - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", Sorting: utils.MetaWeight, SortingParameters: []string{}, - Routes: []*engine.Route{ + Routes: []*engine.ExternalRoute{ { ID: "route1", - Weights: utils.DynamicWeights{{Weight: 20}}, + Weights: ";20", }, { ID: "route2", - Weights: utils.DynamicWeights{{Weight: 10}}, + Weights: ";10", }, }, } - var replyRts *engine.RouteProfile + var replyRts *engine.APIRouteProfile if err := cgrLdrBIRPC.Call(context.Background(), utils.AdminSv1GetRouteProfile, &utils.TenantIDWithAPIOpts{TenantID: &utils.TenantID{Tenant: "cgrates.org", ID: "ROUTE_ACNT_1001"}}, &replyRts); err != nil { diff --git a/console/routes_profile.go b/console/routes_profile.go index 71fea624b..fb545380f 100644 --- a/console/routes_profile.go +++ b/console/routes_profile.go @@ -60,6 +60,6 @@ func (self *CmdGetRoute) PostprocessRpcParams() error { } func (self *CmdGetRoute) RpcResult() interface{} { - var atr engine.RouteProfile + var atr engine.APIRouteProfile return &atr } diff --git a/engine/libroutes.go b/engine/libroutes.go index 8be20d800..c8e54d453 100644 --- a/engine/libroutes.go +++ b/engine/libroutes.go @@ -320,3 +320,97 @@ type RouteWithWeight struct { Weight float64 lazyCheckRules []*FilterRule } + +// ExternalRoute the attribute for external profile +type ExternalRoute struct { + ID string // RouteID + FilterIDs []string + AccountIDs []string + RateProfileIDs []string // used when computing price + ResourceIDs []string // queried in some strategies + StatIDs []string // queried in some strategies + Weights string + Blocker bool // do not process further route after this one + RouteParameters string +} + +// APIRouteProfile used by APIs +type APIRouteProfile struct { + Tenant string + ID string // LCR Profile ID + FilterIDs []string + Sorting string // Sorting strategy + SortingParameters []string + Routes []*ExternalRoute + Weights string +} + +type APIRouteProfileWithAPIOpts struct { + *APIRouteProfile + APIOpts map[string]interface{} +} + +func NewAPIRouteProfile(attr *RouteProfile) (ext *APIRouteProfile) { + ext = &APIRouteProfile{ + Tenant: attr.Tenant, + ID: attr.ID, + FilterIDs: attr.FilterIDs, + Sorting: attr.Sorting, + SortingParameters: attr.SortingParameters, + Routes: make([]*ExternalRoute, len(attr.Routes)), + Weights: attr.Weights.String(utils.InfieldSep, utils.ANDSep), + } + for i, r := range attr.Routes { + ext.Routes[i] = &ExternalRoute{ + ID: r.ID, + FilterIDs: r.FilterIDs, + AccountIDs: r.AccountIDs, + RateProfileIDs: r.RateProfileIDs, + ResourceIDs: r.ResourceIDs, + StatIDs: r.StatIDs, + Weights: r.Weights.String(utils.InfieldSep, utils.ANDSep), + Blocker: r.Blocker, + RouteParameters: r.RouteParameters, + } + } + return +} + +// AsAttributeProfile converts the external attribute format to the actual AttributeProfile +func (ext *APIRouteProfile) AsRouteProfile() (rp *RouteProfile, err error) { + if len(ext.Routes) == 0 { + return nil, utils.NewErrMandatoryIeMissing("Routes") + } + rp = &RouteProfile{ + Tenant: ext.Tenant, + ID: ext.ID, + FilterIDs: ext.FilterIDs, + Sorting: ext.Sorting, + SortingParameters: ext.SortingParameters, + Routes: make([]*Route, len(ext.Routes)), + } + if ext.Weights != utils.EmptyString { + if rp.Weights, err = utils.NewDynamicWeightsFromString(ext.Weights, utils.InfieldSep, utils.ANDSep); err != nil { + return + } + } + for i, extR := range ext.Routes { + rp.Routes[i] = &Route{ + ID: extR.ID, + FilterIDs: extR.FilterIDs, + AccountIDs: extR.AccountIDs, + RateProfileIDs: extR.RateProfileIDs, + ResourceIDs: extR.ResourceIDs, + StatIDs: extR.StatIDs, + Blocker: extR.Blocker, + RouteParameters: extR.RouteParameters, + } + if extR.Weights != utils.EmptyString { + if rp.Routes[i].Weights, err = utils.NewDynamicWeightsFromString(extR.Weights, utils.InfieldSep, utils.ANDSep); err != nil { + return + } + } + } + err = rp.Compile() + return +}