diff --git a/admins/ips.go b/admins/ips.go
new file mode 100644
index 000000000..d0320b981
--- /dev/null
+++ b/admins/ips.go
@@ -0,0 +1,177 @@
+/*
+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 admins
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// GetIPProfile returns an IP configuration
+func (s *AdminS) V1GetIPProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.IPProfile) error {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ ipp, err := s.dm.GetIPProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *reply = *ipp
+ return nil
+}
+
+// GetIPProfileIDs returns list of IPProfile IDs registered for a tenant
+func (s *AdminS) V1GetIPProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, ippIDs *[]string) error {
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ prfx := utils.IPProfilesPrefix + tnt + utils.ConcatenatedKeySep
+ lenPrfx := len(prfx)
+ prfx += args.ItemsPrefix
+ keys, err := s.dm.DataDB().GetKeysForPrefix(ctx, prfx)
+ if err != nil {
+ return err
+ }
+ if len(keys) == 0 {
+ return utils.ErrNotFound
+ }
+ retIDs := make([]string, len(keys))
+ for i, key := range keys {
+ retIDs[i] = key[lenPrfx:]
+ }
+ limit, offset, maxItems, err := utils.GetPaginateOpts(args.APIOpts)
+ if err != nil {
+ return err
+ }
+ *ippIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
+ return err
+}
+
+// GetIPProfiles returns a list of IPProfiles registered for a tenant.
+func (s *AdminS) V1GetIPProfiles(ctx *context.Context, args *utils.ArgsItemIDs, ipps *[]*utils.IPProfile) error {
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ var ippIDs []string
+ if err := s.V1GetIPProfileIDs(ctx, args, &ippIDs); err != nil {
+ return err
+ }
+ *ipps = make([]*utils.IPProfile, 0, len(ippIDs))
+ for _, ippID := range ippIDs {
+ ipp, err := s.dm.GetIPProfile(ctx, tnt, ippID, true, true, utils.NonTransactional)
+ if err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *ipps = append(*ipps, ipp)
+ }
+ return nil
+}
+
+// GetIPProfilesCount returns the total number of IPProfileIDs registered for a tenant
+// returns ErrNotFound in case of 0 IPProfileIDs
+func (s *AdminS) V1GetIPProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) error {
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ prfx := utils.IPProfilesPrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
+ keys, err := s.dm.DataDB().GetKeysForPrefix(ctx, prfx)
+ if err != nil {
+ return err
+ }
+ if len(keys) == 0 {
+ return utils.ErrNotFound
+ }
+ *reply = len(keys)
+ return nil
+}
+
+// SetIPProfile adds a new IP configuration.
+func (s *AdminS) V1SetIPProfile(ctx *context.Context, arg *utils.IPProfileWithAPIOpts, reply *string) error {
+ if missing := utils.MissingStructFields(arg.IPProfile, []string{utils.ID}); len(missing) != 0 {
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ if arg.Tenant == utils.EmptyString {
+ arg.Tenant = s.cfg.GeneralCfg().DefaultTenant
+ }
+ if err := s.dm.SetIPProfile(ctx, arg.IPProfile, true); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ //generate a loadID for CacheIPProfiles and CacheIPs and store it in database
+ //make 1 insert for both IPProfile and IPs instead of 2
+ loadID := time.Now().UnixNano()
+ if err := s.dm.SetLoadIDs(ctx,
+ map[string]int64{utils.CacheIPProfiles: loadID,
+ utils.CacheIPs: loadID}); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ // delay if needed before cache call
+ if s.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", s.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(s.cfg.GeneralCfg().CachingDelay)
+ }
+ //handle caching for IPProfile
+ if err := s.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), arg.Tenant, utils.CacheIPProfiles,
+ arg.TenantID(), utils.EmptyString, &arg.FilterIDs, arg.APIOpts); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *reply = utils.OK
+ return nil
+}
+
+// RemoveIPProfile remove a specific IP configuration.
+func (s *AdminS) V1RemoveIPProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *string) error {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ if err := s.dm.RemoveIPProfile(ctx, tnt, arg.ID, true); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ // delay if needed before cache call
+ if s.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", s.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(s.cfg.GeneralCfg().CachingDelay)
+ }
+ //handle caching for IPProfile
+ if err := s.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheIPProfiles,
+ utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ //generate a loadID for CacheIPProfiles and CacheIPs and store it in database
+ //make 1 insert for both IPProfile and IPs instead of 2
+ loadID := time.Now().UnixNano()
+ if err := s.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheIPProfiles: loadID, utils.CacheIPs: loadID}); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *reply = utils.OK
+ return nil
+}
diff --git a/admins/libadmin.go b/admins/libadmin.go
index d4703f77a..cfca4466a 100644
--- a/admins/libadmin.go
+++ b/admins/libadmin.go
@@ -79,6 +79,8 @@ func (admS *AdminS) CallCache(ctx *context.Context, cacheopt string, tnt, cacheI
cacheIDs = append(cacheIDs, utils.CacheThresholds)
case utils.CacheResourceProfiles:
cacheIDs = append(cacheIDs, utils.CacheResources)
+ case utils.CacheIPProfiles:
+ cacheIDs = append(cacheIDs, utils.CacheIPs)
case utils.CacheStatQueueProfiles:
cacheIDs = append(cacheIDs, utils.CacheStatQueues)
}
@@ -103,6 +105,8 @@ func (admS *AdminS) composeArgsReload(ctx *context.Context, tnt, cacheID, itemID
argCache[utils.CacheThresholds] = []string{itemID}
case utils.CacheResourceProfiles:
argCache[utils.CacheResources] = []string{itemID}
+ case utils.CacheIPProfiles:
+ argCache[utils.CacheIPs] = []string{itemID}
case utils.CacheStatQueueProfiles:
argCache[utils.CacheStatQueues] = []string{itemID}
}
diff --git a/apis/ips.go b/apis/ips.go
new file mode 100644
index 000000000..079da9297
--- /dev/null
+++ b/apis/ips.go
@@ -0,0 +1,177 @@
+/*
+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 apis
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// GetIPProfile returns an IP configuration
+func (s *AdminSv1) GetIPProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.IPProfile) error {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ ipp, err := s.dm.GetIPProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *reply = *ipp
+ return nil
+}
+
+// GetIPProfileIDs returns list of IPProfile IDs registered for a tenant
+func (s *AdminSv1) GetIPProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, ippIDs *[]string) error {
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ prfx := utils.IPProfilesPrefix + tnt + utils.ConcatenatedKeySep
+ lenPrfx := len(prfx)
+ prfx += args.ItemsPrefix
+ keys, err := s.dm.DataDB().GetKeysForPrefix(ctx, prfx)
+ if err != nil {
+ return err
+ }
+ if len(keys) == 0 {
+ return utils.ErrNotFound
+ }
+ retIDs := make([]string, len(keys))
+ for i, key := range keys {
+ retIDs[i] = key[lenPrfx:]
+ }
+ limit, offset, maxItems, err := utils.GetPaginateOpts(args.APIOpts)
+ if err != nil {
+ return err
+ }
+ *ippIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
+ return err
+}
+
+// GetIPProfiles returns a list of IPProfiles registered for a tenant.
+func (s *AdminSv1) GetIPProfiles(ctx *context.Context, args *utils.ArgsItemIDs, ipps *[]*utils.IPProfile) error {
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ var ippIDs []string
+ if err := s.GetIPProfileIDs(ctx, args, &ippIDs); err != nil {
+ return err
+ }
+ *ipps = make([]*utils.IPProfile, 0, len(ippIDs))
+ for _, ippID := range ippIDs {
+ ipp, err := s.dm.GetIPProfile(ctx, tnt, ippID, true, true, utils.NonTransactional)
+ if err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *ipps = append(*ipps, ipp)
+ }
+ return nil
+}
+
+// GetIPProfilesCount returns the total number of IPProfileIDs registered for a tenant
+// returns ErrNotFound in case of 0 IPProfileIDs
+func (s *AdminSv1) GetIPProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) error {
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ prfx := utils.IPProfilesPrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
+ keys, err := s.dm.DataDB().GetKeysForPrefix(ctx, prfx)
+ if err != nil {
+ return err
+ }
+ if len(keys) == 0 {
+ return utils.ErrNotFound
+ }
+ *reply = len(keys)
+ return nil
+}
+
+// SetIPProfile adds a new IP configuration.
+func (s *AdminSv1) SetIPProfile(ctx *context.Context, arg *utils.IPProfileWithAPIOpts, reply *string) error {
+ if missing := utils.MissingStructFields(arg.IPProfile, []string{utils.ID}); len(missing) != 0 {
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ if arg.Tenant == utils.EmptyString {
+ arg.Tenant = s.cfg.GeneralCfg().DefaultTenant
+ }
+ if err := s.dm.SetIPProfile(ctx, arg.IPProfile, true); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ //generate a loadID for CacheIPProfiles and CacheIPs and store it in database
+ //make 1 insert for both IPProfile and IPs instead of 2
+ loadID := time.Now().UnixNano()
+ if err := s.dm.SetLoadIDs(ctx,
+ map[string]int64{utils.CacheIPProfiles: loadID,
+ utils.CacheIPs: loadID}); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ // delay if needed before cache call
+ if s.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", s.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(s.cfg.GeneralCfg().CachingDelay)
+ }
+ //handle caching for IPProfile
+ if err := s.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), arg.Tenant, utils.CacheIPProfiles,
+ arg.TenantID(), utils.EmptyString, &arg.FilterIDs, arg.APIOpts); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *reply = utils.OK
+ return nil
+}
+
+// RemoveIPProfile remove a specific IP configuration.
+func (s *AdminSv1) RemoveIPProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *string) error {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+ if err := s.dm.RemoveIPProfile(ctx, tnt, arg.ID, true); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ // delay if needed before cache call
+ if s.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", s.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(s.cfg.GeneralCfg().CachingDelay)
+ }
+ //handle caching for IPProfile
+ if err := s.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheIPProfiles,
+ utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ //generate a loadID for CacheIPProfiles and CacheIPs and store it in database
+ //make 1 insert for both IPProfile and IPs instead of 2
+ loadID := time.Now().UnixNano()
+ if err := s.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheIPProfiles: loadID, utils.CacheIPs: loadID}); err != nil {
+ return utils.APIErrorHandler(err)
+ }
+ *reply = utils.OK
+ return nil
+}
diff --git a/apis/libadmin.go b/apis/libadmin.go
index 9e5636f2d..d32ffedd2 100644
--- a/apis/libadmin.go
+++ b/apis/libadmin.go
@@ -79,6 +79,8 @@ func (admS *AdminSv1) CallCache(ctx *context.Context, cacheopt string, tnt, cach
cacheIDs = append(cacheIDs, utils.CacheThresholds)
case utils.CacheResourceProfiles:
cacheIDs = append(cacheIDs, utils.CacheResources)
+ case utils.CacheIPProfiles:
+ cacheIDs = append(cacheIDs, utils.CacheIPs)
case utils.CacheStatQueueProfiles:
cacheIDs = append(cacheIDs, utils.CacheStatQueues)
}
@@ -103,6 +105,8 @@ func (admS *AdminSv1) composeArgsReload(ctx *context.Context, tnt, cacheID, item
argCache[utils.CacheThresholds] = []string{itemID}
case utils.CacheResourceProfiles:
argCache[utils.CacheResources] = []string{itemID}
+ case utils.CacheIPProfiles:
+ argCache[utils.CacheIPs] = []string{itemID}
case utils.CacheStatQueueProfiles:
argCache[utils.CacheStatQueues] = []string{itemID}
}
diff --git a/apis/loaders_it_test.go b/apis/loaders_it_test.go
index 67097c45a..33cc7de7d 100644
--- a/apis/loaders_it_test.go
+++ b/apis/loaders_it_test.go
@@ -63,6 +63,7 @@ var (
testLoadersGetFilters,
testLoadersGetRateProfiles,
testLoadersGetResourceProfiles,
+ testLoadersGetIPProfiles,
testLoadersGetRouteProfiles,
testLoadersGetStatQueueProfiles,
testLoadersGetThresholdProfiles,
@@ -275,6 +276,17 @@ cgrates.org,ResGroup22,*string:~*req.Account:dan,;10,3600s,2,premium_call,true,t
t.Fatal(err)
}
+ // Create and populate IPs.csv
+ if err := writeFile(utils.IPsCsv, `
+#Tenant[0],Id[1],FilterIDs[2],Weights[3],TTL[4],Type[5],AddressPool[6],Allocation[7],Stored[8]
+cgrates.org,IPs1,*string:~*req.Account:1001,;10,1s,ipv4,172.16.1.1/24,alloc_success,true
+cgrates.org,IPs1,,,,,,,
+cgrates.org,IPs2,,,,,,,
+cgrates.org,IPs2,*string:~*req.Account:1002,;20,1h,ipv4,127.0.0.1/24,alloc_new,false
+`); err != nil {
+ t.Fatal(err)
+ }
+
// Create and populate Routes.csv
if err := writeFile(utils.RoutesCsv, `
#Tenant[0],ID[1],FilterIDs[2],Weights[3],Blockers[4],Sorting[5],SortingParameters[6],RouteID[7],RouteFilterIDs[8],RouteAccountIDs[9],RouteRateProfileIDs[10],RouteResourceIDs[11],RouteStatIDs[12],RouteWeights[13],RouteBlockers[14],RouteParameters[15]
@@ -973,6 +985,55 @@ func testLoadersGetResourceProfiles(t *testing.T) {
}
}
+func testLoadersGetIPProfiles(t *testing.T) {
+ expIPPs := []*utils.IPProfile{
+ {
+ Tenant: "cgrates.org",
+ ID: "IPs1",
+ FilterIDs: []string{"*string:~*req.Account:1001"},
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 10,
+ },
+ },
+ TTL: time.Second,
+ Type: "ipv4",
+ AddressPool: "172.16.1.1/24",
+ Allocation: "alloc_success",
+ Stored: true,
+ },
+ {
+ Tenant: "cgrates.org",
+ ID: "IPs2",
+ FilterIDs: []string{"*string:~*req.Account:1002"},
+ Weights: utils.DynamicWeights{
+ {
+ Weight: 20,
+ },
+ },
+ TTL: time.Hour,
+ Type: "ipv4",
+ AddressPool: "127.0.0.1/24",
+ Allocation: "alloc_new",
+ Stored: false,
+ },
+ }
+ var ipps []*utils.IPProfile
+ if err := ldrRPC.Call(context.Background(), utils.AdminSv1GetIPProfiles,
+ &utils.ArgsItemIDs{
+ Tenant: "cgrates.org",
+ }, &ipps); err != nil {
+ t.Error(err)
+ } else {
+ sort.Slice(ipps, func(i, j int) bool {
+ return ipps[i].ID < ipps[j].ID
+ })
+ if !reflect.DeepEqual(ipps, expIPPs) {
+ t.Errorf("expected: <%+v>, \nreceived: <%+v>", utils.ToJSON(expIPPs), utils.ToJSON(ipps))
+ }
+ }
+}
+
func testLoadersGetRouteProfiles(t *testing.T) {
expRouPrfs := []*utils.RouteProfile{
{
diff --git a/apis/replicator.go b/apis/replicator.go
index 40aabffb1..2882ed94e 100644
--- a/apis/replicator.go
+++ b/apis/replicator.go
@@ -156,6 +156,28 @@ func (rplSv1 *ReplicatorSv1) GetResourceProfile(ctx *context.Context, tntID *uti
return nil
}
+// GetIP is the remote method coresponding to the dataDb driver method
+func (rplSv1 *ReplicatorSv1) GetIP(ctx *context.Context, tntID *utils.TenantIDWithAPIOpts, reply *utils.IP) error {
+ engine.UpdateReplicationFilters(utils.IPsPrefix, tntID.TenantID.TenantID(), utils.IfaceAsString(tntID.APIOpts[utils.RemoteHostOpt]))
+ rcv, err := rplSv1.dm.DataDB().GetIPDrv(ctx, tntID.Tenant, tntID.ID)
+ if err != nil {
+ return err
+ }
+ *reply = *rcv
+ return nil
+}
+
+// GetIPProfile is the remote method coresponding to the dataDb driver method
+func (rplSv1 *ReplicatorSv1) GetIPProfile(ctx *context.Context, tntID *utils.TenantIDWithAPIOpts, reply *utils.IPProfile) error {
+ engine.UpdateReplicationFilters(utils.IPProfilesPrefix, tntID.TenantID.TenantID(), utils.IfaceAsString(tntID.APIOpts[utils.RemoteHostOpt]))
+ rcv, err := rplSv1.dm.DataDB().GetIPProfileDrv(ctx, tntID.Tenant, tntID.ID)
+ if err != nil {
+ return err
+ }
+ *reply = *rcv
+ return nil
+}
+
// GetRouteProfile is the remote method coresponding to the dataDb driver method
func (rplSv1 *ReplicatorSv1) GetRouteProfile(ctx *context.Context, tntID *utils.TenantIDWithAPIOpts, reply *utils.RouteProfile) error {
engine.UpdateReplicationFilters(utils.RouteProfilePrefix, tntID.TenantID.TenantID(), utils.IfaceAsString(tntID.APIOpts[utils.RemoteHostOpt]))
@@ -383,6 +405,42 @@ func (rplSv1 *ReplicatorSv1) SetResource(ctx *context.Context, rs *utils.Resourc
return
}
+// SetIPProfile is the replication method coresponding to the dataDb driver method
+func (rplSv1 *ReplicatorSv1) SetIPProfile(ctx *context.Context, ipp *utils.IPProfileWithAPIOpts, reply *string) (err error) {
+ if err = rplSv1.dm.DataDB().SetIPProfileDrv(ctx, ipp.IPProfile); err != nil {
+ return
+ }
+ // delay if needed before cache call
+ if rplSv1.v1.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", rplSv1.v1.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(rplSv1.v1.cfg.GeneralCfg().CachingDelay)
+ }
+ if err = rplSv1.v1.CallCache(ctx, utils.IfaceAsString(ipp.APIOpts[utils.MetaCache]),
+ ipp.Tenant, utils.CacheIPProfiles, ipp.TenantID(), utils.EmptyString, &ipp.FilterIDs, ipp.APIOpts); err != nil {
+ return
+ }
+ *reply = utils.OK
+ return
+}
+
+// SetIP is the replication method coresponding to the dataDb driver method
+func (rplSv1 *ReplicatorSv1) SetIP(ctx *context.Context, ip *utils.IPWithAPIOpts, reply *string) (err error) {
+ if err = rplSv1.dm.DataDB().SetIPDrv(ctx, ip.IP); err != nil {
+ return
+ }
+ // delay if needed before cache call
+ if rplSv1.v1.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", rplSv1.v1.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(rplSv1.v1.cfg.GeneralCfg().CachingDelay)
+ }
+ if err = rplSv1.v1.CallCache(ctx, utils.IfaceAsString(ip.APIOpts[utils.MetaCache]),
+ ip.Tenant, utils.CacheIPs, ip.TenantID(), utils.EmptyString, nil, ip.APIOpts); err != nil {
+ return
+ }
+ *reply = utils.OK
+ return
+}
+
// SetRouteProfile is the replication method coresponding to the dataDb driver method
func (rplSv1 *ReplicatorSv1) SetRouteProfile(ctx *context.Context, sp *utils.RouteProfileWithAPIOpts, reply *string) (err error) {
if err = rplSv1.dm.DataDB().SetRouteProfileDrv(ctx, sp.RouteProfile); err != nil {
@@ -643,6 +701,42 @@ func (rplSv1 *ReplicatorSv1) RemoveResourceProfile(ctx *context.Context, args *u
return
}
+// RemoveIP is the replication method coresponding to the dataDb driver method
+func (rplSv1 *ReplicatorSv1) RemoveIP(ctx *context.Context, args *utils.TenantIDWithAPIOpts, reply *string) (err error) {
+ if err = rplSv1.dm.DataDB().RemoveIPDrv(ctx, args.Tenant, args.ID); err != nil {
+ return
+ }
+ // delay if needed before cache call
+ if rplSv1.v1.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", rplSv1.v1.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(rplSv1.v1.cfg.GeneralCfg().CachingDelay)
+ }
+ if err = rplSv1.v1.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]),
+ args.Tenant, utils.CacheIPs, args.TenantID.TenantID(), utils.EmptyString, nil, args.APIOpts); err != nil {
+ return
+ }
+ *reply = utils.OK
+ return
+}
+
+// RemoveIPProfile is the replication method coresponding to the dataDb driver method
+func (rplSv1 *ReplicatorSv1) RemoveIPProfile(ctx *context.Context, args *utils.TenantIDWithAPIOpts, reply *string) (err error) {
+ if err = rplSv1.dm.DataDB().RemoveIPProfileDrv(ctx, args.Tenant, args.ID); err != nil {
+ return
+ }
+ // delay if needed before cache call
+ if rplSv1.v1.cfg.GeneralCfg().CachingDelay != 0 {
+ utils.Logger.Info(fmt.Sprintf(" Delaying cache call for %v", rplSv1.v1.cfg.GeneralCfg().CachingDelay))
+ time.Sleep(rplSv1.v1.cfg.GeneralCfg().CachingDelay)
+ }
+ if err = rplSv1.v1.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]),
+ args.Tenant, utils.CacheIPProfiles, args.TenantID.TenantID(), utils.EmptyString, nil, args.APIOpts); err != nil {
+ return
+ }
+ *reply = utils.OK
+ return
+}
+
// RemoveRouteProfile is the replication method coresponding to the dataDb driver method
func (rplSv1 *ReplicatorSv1) RemoveRouteProfile(ctx *context.Context, args *utils.TenantIDWithAPIOpts, reply *string) (err error) {
if err = rplSv1.dm.DataDB().RemoveRouteProfileDrv(ctx, args.Tenant, args.ID); err != nil {
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index c263c4492..61d591a25 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -217,6 +217,7 @@ func runCGREngine(fs []string) (err error) {
services.NewChargerService(cfg),
services.NewRouteService(cfg),
services.NewResourceService(cfg),
+ services.NewIPService(cfg),
services.NewTrendService(cfg),
services.NewRankingService(cfg),
services.NewThresholdService(cfg),
diff --git a/config/config.go b/config/config.go
index b2c0b5ad8..3d6414e8a 100644
--- a/config/config.go
+++ b/config/config.go
@@ -201,6 +201,11 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) {
UsageTTL: []*DynamicDurationOpt{{value: ResourcesUsageTTLDftOpt}},
Units: []*DynamicFloat64Opt{{value: ResourcesUnitsDftOpt}},
}},
+ ipsCfg: &IPsCfg{Opts: &IPsOpts{
+ UsageID: []*DynamicStringOpt{{value: IPsUsageIDDftOpt}},
+ TTL: []*DynamicDurationOpt{{value: IPsTTLDftOpt}},
+ Units: []*DynamicFloat64Opt{{value: IPsUnitsDftOpt}},
+ }},
trendSCfg: new(TrendSCfg),
rankingSCfg: new(RankingSCfg),
statsCfg: &StatSCfg{Opts: &StatsOpts{
@@ -356,6 +361,7 @@ type CGRConfig struct {
attributeSCfg *AttributeSCfg // AttributeS config
chargerSCfg *ChargerSCfg // ChargerS config
resourceSCfg *ResourceSConfig // ResourceS config
+ ipsCfg *IPsCfg // IPs config
statsCfg *StatSCfg // StatS config
thresholdSCfg *ThresholdSCfg // ThresholdS config
routeSCfg *RouteSCfg // RouteS config
@@ -393,11 +399,11 @@ func (cfg *CGRConfig) ConfigDB() ConfigDB {
return nil
}
-var posibleLoaderTypes = utils.NewStringSet([]string{utils.MetaAttributes,
- utils.MetaResources, utils.MetaFilters, utils.MetaStats, utils.MetaTrends,
- utils.MetaRoutes, utils.MetaThresholds, utils.MetaChargers, utils.MetaRankings,
- utils.MetaRateProfiles,
- utils.MetaAccounts, utils.MetaActionProfiles})
+var possibleLoaderTypes = utils.NewStringSet([]string{utils.MetaAttributes,
+ utils.MetaResources, utils.MetaIPs, utils.MetaFilters, utils.MetaStats,
+ utils.MetaTrends, utils.MetaRoutes, utils.MetaThresholds, utils.MetaChargers,
+ utils.MetaRankings, utils.MetaRateProfiles, utils.MetaAccounts,
+ utils.MetaActionProfiles})
var possibleReaderTypes = utils.NewStringSet([]string{utils.MetaFileCSV,
utils.MetaKafkajsonMap, utils.MetaFileXML, utils.MetaSQL, utils.MetaFileFWV,
@@ -487,6 +493,13 @@ func (cfg *CGRConfig) ResourceSCfg() *ResourceSConfig { // not done
return cfg.resourceSCfg
}
+// IPsCfg returns the config for IPs.
+func (cfg *CGRConfig) IPsCfg() *IPsCfg {
+ cfg.lks[IPsJSON].Lock()
+ defer cfg.lks[IPsJSON].Unlock()
+ return cfg.ipsCfg
+}
+
// StatSCfg returns the config for StatS
func (cfg *CGRConfig) StatSCfg() *StatSCfg { // not done
cfg.lks[StatSJSON].Lock()
@@ -1002,7 +1015,7 @@ func (cfg *CGRConfig) initChanels() {
func (cfg *CGRConfig) reloadSections(sections ...string) {
subsystemsThatNeedDataDB := utils.NewStringSet([]string{DataDBJSON,
CDRsJSON, SessionSJSON, AttributeSJSON,
- ChargerSJSON, ResourceSJSON, StatSJSON, ThresholdSJSON,
+ ChargerSJSON, ResourceSJSON, IPsJSON, StatSJSON, ThresholdSJSON,
RouteSJSON, LoaderSJSON, RateSJSON, AdminSJSON, AccountSJSON,
ActionSJSON})
subsystemsThatNeedStorDB := utils.NewStringSet([]string{StorDBJSON, CDRsJSON})
@@ -1068,6 +1081,7 @@ func (cfg *CGRConfig) Clone() (cln *CGRConfig) {
attributeSCfg: cfg.attributeSCfg.Clone(),
chargerSCfg: cfg.chargerSCfg.Clone(),
resourceSCfg: cfg.resourceSCfg.Clone(),
+ ipsCfg: cfg.ipsCfg.Clone(),
statsCfg: cfg.statsCfg.Clone(),
thresholdSCfg: cfg.thresholdSCfg.Clone(),
trendSCfg: cfg.trendSCfg.Clone(),
diff --git a/config/config_defaults.go b/config/config_defaults.go
index 62fc34afb..9dbf293c1 100644
--- a/config/config_defaults.go
+++ b/config/config_defaults.go
@@ -123,6 +123,8 @@ const CGRATES_CFG_JSON = `
"*actions": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*resource_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*resources": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
+ "*ip_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
+ "*ips": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*statqueue_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*statqueues": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*threshold_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
@@ -136,6 +138,7 @@ const CGRATES_CFG_JSON = `
"*load_ids": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*versions": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
"*resource_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false},
+ "*ip_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false},
"*stat_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false},
"*threshold_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false},
"*ranking_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate":false},
@@ -268,6 +271,9 @@ const CGRATES_CFG_JSON = `
"*resource_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control resource profiles caching
"*resources": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control resources caching
"*event_resources": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // matching resources to events
+ "*ip_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control ip profiles caching
+ "*ips": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control ips caching
+ "*event_ips": {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // matching ips to events
"*statqueue_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // statqueue profiles
"*statqueues": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // statqueues with metrics
"*threshold_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control threshold profiles caching
@@ -282,6 +288,7 @@ const CGRATES_CFG_JSON = `
"*action_profiles": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control action profile caching
"*accounts": {"limit": -1, "ttl": "", "static_ttl": false, "precache": false, "remote":false, "replicate": false}, // control account profile caching
"*resource_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control resource filter indexes caching
+ "*ip_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control ip filter indexes caching
"*stat_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control stat filter indexes caching
"*threshold_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control threshold filter indexes caching
"*route_filter_indexes" : {"limit": -1, "ttl": "", "static_ttl": false, "remote":false, "replicate": false}, // control route filter indexes caching
@@ -1136,6 +1143,41 @@ const CGRATES_CFG_JSON = `
}
},
+"ips": {
+ "enabled": false, // enables the IPs service:
+ "store_interval": "", // dump cache regularly to dataDB, 0 - dump at start/shutdown: <""|$dur>
+ "indexed_selects": true, // enable profile matching exclusively on indexes
+ //"string_indexed_fields": [], // query indexes based on these fields for faster processing
+ "prefix_indexed_fields": [], // query indexes based on these fields for faster processing
+ "suffix_indexed_fields": [], // query indexes based on these fields for faster processing
+ "exists_indexed_fields": [], // query indexes based on these fields for faster processing
+ "notexists_indexed_fields": [], // query indexes based on these fields for faster processing
+ "nested_fields": false, // determines which field is checked when matching indexed filters(true: all; false: only the one on the first level)
+ "opts":{
+ // "*usageID": [
+ // {
+ // "Tenant": "*any",
+ // "FilterIDs": [],
+ // "Value": ""
+ // }
+ // ],
+ // "*ttl": [
+ // {
+ // "Tenant": "*any",
+ // "FilterIDs": [],
+ // "Value": "72h"
+ // }
+ // ],
+ // "*units": [
+ // {
+ // "Tenant": "*any",
+ // "FilterIDs": [],
+ // "Value": 1
+ // }
+ // ]
+ }
+},
+
"stats": {
"enabled": false, // starts Stat service:
@@ -1328,6 +1370,7 @@ const CGRATES_CFG_JSON = `
"*filters":{"limit": -1, "ttl": "5s", "static_ttl": false},
"*attributes":{"limit": -1, "ttl": "5s", "static_ttl": false},
"*resources":{"limit": -1, "ttl": "5s", "static_ttl": false},
+ "*ips":{"limit": -1, "ttl": "5s", "static_ttl": false},
"*stats":{"limit": -1, "ttl": "5s", "static_ttl": false},
"*thresholds":{"limit": -1, "ttl": "5s", "static_ttl": false},
"*routes":{"limit": -1, "ttl": "5s", "static_ttl": false},
@@ -1382,6 +1425,21 @@ const CGRATES_CFG_JSON = `
{"tag": "ThresholdIDs", "path": "ThresholdIDs", "type": "*variable", "value": "~*req.9"}
]
},
+ {
+ "type": "*ips", // data source type
+ "file_name": "IPs.csv", // file name in the tp_in_dir
+ "fields": [
+ {"tag": "Tenant", "path": "Tenant", "type": "*variable", "value": "~*req.0", "mandatory": true},
+ {"tag": "ID", "path": "ID", "type": "*variable", "value": "~*req.1", "mandatory": true},
+ {"tag": "FilterIDs", "path": "FilterIDs", "type": "*variable", "value": "~*req.2"},
+ {"tag": "Weights", "path": "Weights", "type": "*variable", "value": "~*req.3"},
+ {"tag": "TTL", "path": "TTL", "type": "*variable", "value": "~*req.4"},
+ {"tag": "Type", "path": "Type", "type": "*variable", "value": "~*req.5"},
+ {"tag": "AddressPool", "path": "AddressPool", "type": "*variable", "value": "~*req.6"},
+ {"tag": "Allocation", "path": "Allocation", "type": "*variable", "value": "~*req.7"},
+ {"tag": "Stored", "path": "Stored", "type": "*variable", "value": "~*req.8"},
+ ]
+ },
{
"type": "*stats", // data source type
"file_name": "Stats.csv", // file name in the tp_in_dir
diff --git a/config/config_json.go b/config/config_json.go
index eea6016f7..88072fc25 100644
--- a/config/config_json.go
+++ b/config/config_json.go
@@ -45,6 +45,7 @@ const (
PrometheusAgentJSON = "prometheus_agent"
AttributeSJSON = "attributes"
ResourceSJSON = "resources"
+ IPsJSON = "ips"
JanusAgentJSON = "janus_agent"
StatSJSON = "stats"
ThresholdSJSON = "thresholds"
@@ -88,6 +89,7 @@ var (
RankingSJSON: utils.RankingS,
StatSJSON: utils.StatS,
ResourceSJSON: utils.ResourceS,
+ IPsJSON: utils.IPs,
RouteSJSON: utils.RouteS,
AdminSJSON: utils.AdminS,
CDRsJSON: utils.CDRServer,
@@ -193,6 +195,7 @@ func newSections(cfg *CGRConfig) Sections {
cfg.attributeSCfg,
cfg.chargerSCfg,
cfg.resourceSCfg,
+ cfg.ipsCfg,
cfg.statsCfg,
cfg.thresholdSCfg,
cfg.rankingSCfg,
diff --git a/config/config_json_test.go b/config/config_json_test.go
index a017ca2f5..a9e1485c5 100644
--- a/config/config_json_test.go
+++ b/config/config_json_test.go
@@ -100,6 +100,15 @@ func TestCacheJsonCfg(t *testing.T) {
utils.CacheEventResources: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ utils.CacheIPProfiles: {Limit: utils.IntPointer(-1),
+ Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ utils.CacheIPs: {Limit: utils.IntPointer(-1),
+ Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
+ Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ utils.CacheEventIPs: {Limit: utils.IntPointer(-1),
+ Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheStatQueueProfiles: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
Precache: utils.BoolPointer(false), Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
@@ -142,6 +151,9 @@ func TestCacheJsonCfg(t *testing.T) {
utils.CacheResourceFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
+ utils.CacheIPFilterIndexes: {Limit: utils.IntPointer(-1),
+ Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
+ Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
utils.CacheStatFilterIndexes: {Limit: utils.IntPointer(-1),
Ttl: utils.StringPointer(""), Static_ttl: utils.BoolPointer(false),
Remote: utils.BoolPointer(false), Replicate: utils.BoolPointer(false)},
@@ -318,6 +330,13 @@ func TestDfDataDbJsonCfg(t *testing.T) {
Replicate: utils.BoolPointer(false),
Remote: utils.BoolPointer(false),
},
+ utils.MetaIPProfiles: {
+ Ttl: utils.StringPointer(utils.EmptyString),
+ Static_ttl: utils.BoolPointer(false),
+ Limit: utils.IntPointer(-1),
+ Replicate: utils.BoolPointer(false),
+ Remote: utils.BoolPointer(false),
+ },
utils.MetaStatQueues: {
Ttl: utils.StringPointer(utils.EmptyString),
Static_ttl: utils.BoolPointer(false),
@@ -332,6 +351,13 @@ func TestDfDataDbJsonCfg(t *testing.T) {
Replicate: utils.BoolPointer(false),
Remote: utils.BoolPointer(false),
},
+ utils.MetaIPs: {
+ Ttl: utils.StringPointer(utils.EmptyString),
+ Static_ttl: utils.BoolPointer(false),
+ Limit: utils.IntPointer(-1),
+ Replicate: utils.BoolPointer(false),
+ Remote: utils.BoolPointer(false),
+ },
utils.MetaStatQueueProfiles: {
Ttl: utils.StringPointer(utils.EmptyString),
Static_ttl: utils.BoolPointer(false),
@@ -416,6 +442,13 @@ func TestDfDataDbJsonCfg(t *testing.T) {
Replicate: utils.BoolPointer(false),
Remote: utils.BoolPointer(false),
},
+ utils.CacheIPFilterIndexes: {
+ Ttl: utils.StringPointer(utils.EmptyString),
+ Static_ttl: utils.BoolPointer(false),
+ Limit: utils.IntPointer(-1),
+ Replicate: utils.BoolPointer(false),
+ Remote: utils.BoolPointer(false),
+ },
utils.CacheStatFilterIndexes: {
Ttl: utils.StringPointer(utils.EmptyString),
Static_ttl: utils.BoolPointer(false),
@@ -1114,6 +1147,50 @@ func TestDfLoaderJsonCfg(t *testing.T) {
Value: utils.StringPointer("~*req.9")},
},
},
+ {
+ Type: utils.StringPointer(utils.MetaIPs),
+ File_name: utils.StringPointer(utils.IPsCsv),
+ Fields: &[]*FcTemplateJsonCfg{
+ {Tag: utils.StringPointer(utils.Tenant),
+ Path: utils.StringPointer(utils.Tenant),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.0"),
+ Mandatory: utils.BoolPointer(true)},
+ {Tag: utils.StringPointer(utils.ID),
+ Path: utils.StringPointer(utils.ID),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.1"),
+ Mandatory: utils.BoolPointer(true)},
+ {Tag: utils.StringPointer("FilterIDs"),
+ Path: utils.StringPointer("FilterIDs"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.2")},
+ {Tag: utils.StringPointer("Weights"),
+ Path: utils.StringPointer("Weights"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.3")},
+ {Tag: utils.StringPointer("TTL"),
+ Path: utils.StringPointer("TTL"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.4")},
+ {Tag: utils.StringPointer("Type"),
+ Path: utils.StringPointer("Type"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.5")},
+ {Tag: utils.StringPointer("AddressPool"),
+ Path: utils.StringPointer("AddressPool"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.6")},
+ {Tag: utils.StringPointer("Allocation"),
+ Path: utils.StringPointer("Allocation"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.7")},
+ {Tag: utils.StringPointer("Stored"),
+ Path: utils.StringPointer("Stored"),
+ Type: utils.StringPointer(utils.MetaVariable),
+ Value: utils.StringPointer("~*req.8")},
+ },
+ },
{
Type: utils.StringPointer(utils.MetaStats),
File_name: utils.StringPointer(utils.StatsCsv),
@@ -1692,6 +1769,7 @@ func TestDfLoaderJsonCfg(t *testing.T) {
utils.MetaFilters: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
utils.MetaAttributes: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
utils.MetaResources: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
+ utils.MetaIPs: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
utils.MetaStats: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
utils.MetaThresholds: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
utils.MetaRoutes: {Limit: utils.IntPointer(-1), Ttl: utils.StringPointer("5s"), Static_ttl: utils.BoolPointer(false)},
diff --git a/config/config_test.go b/config/config_test.go
index a55822241..46c6d6e1a 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -435,10 +435,12 @@ func TestCgrCfgJSONDefaultsSMGenericCfg(t *testing.T) {
func TestCgrCfgJSONDefaultsCacheCFG(t *testing.T) {
eCacheCfg := &CacheCfg{
Partitions: map[string]*CacheParamCfg{
- utils.CacheResourceProfiles: {Limit: -1},
- utils.CacheResources: {Limit: -1},
- utils.CacheEventResources: {Limit: -1,
- TTL: 0},
+ utils.CacheResourceProfiles: {Limit: -1},
+ utils.CacheResources: {Limit: -1},
+ utils.CacheEventResources: {Limit: -1, TTL: 0},
+ utils.CacheIPProfiles: {Limit: -1},
+ utils.CacheIPs: {Limit: -1},
+ utils.CacheEventIPs: {Limit: -1, TTL: 0},
utils.CacheStatQueueProfiles: {Limit: -1},
utils.CacheStatQueues: {Limit: -1},
utils.CacheThresholdProfiles: {Limit: -1},
@@ -453,6 +455,7 @@ func TestCgrCfgJSONDefaultsCacheCFG(t *testing.T) {
utils.CacheActionProfiles: {Limit: -1},
utils.CacheAccounts: {Limit: -1},
utils.CacheResourceFilterIndexes: {Limit: -1},
+ utils.CacheIPFilterIndexes: {Limit: -1},
utils.CacheStatFilterIndexes: {Limit: -1},
utils.CacheThresholdFilterIndexes: {Limit: -1},
utils.CacheRouteFilterIndexes: {Limit: -1},
@@ -1865,6 +1868,7 @@ func TestLoaderConfig(t *testing.T) {
utils.MetaFilters: {Limit: -1, TTL: 5 * time.Second},
utils.MetaAttributes: {Limit: -1, TTL: 5 * time.Second},
utils.MetaResources: {Limit: -1, TTL: 5 * time.Second},
+ utils.MetaIPs: {Limit: -1, TTL: 5 * time.Second},
utils.MetaStats: {Limit: -1, TTL: 5 * time.Second},
utils.MetaThresholds: {Limit: -1, TTL: 5 * time.Second},
utils.MetaRoutes: {Limit: -1, TTL: 5 * time.Second},
@@ -2219,6 +2223,7 @@ func TestCgrLoaderCfgITDefaults(t *testing.T) {
utils.MetaFilters: {Limit: -1, TTL: 5 * time.Second},
utils.MetaAttributes: {Limit: -1, TTL: 5 * time.Second},
utils.MetaResources: {Limit: -1, TTL: 5 * time.Second},
+ utils.MetaIPs: {Limit: -1, TTL: 5 * time.Second},
utils.MetaStats: {Limit: -1, TTL: 5 * time.Second},
utils.MetaThresholds: {Limit: -1, TTL: 5 * time.Second},
utils.MetaRoutes: {Limit: -1, TTL: 5 * time.Second},
@@ -2394,6 +2399,59 @@ func TestCgrLoaderCfgITDefaults(t *testing.T) {
Layout: time.RFC3339},
},
},
+ {
+ Type: utils.MetaIPs,
+ Filename: utils.IPsCsv,
+ Fields: []*FCTemplate{
+ {Tag: "Tenant",
+ Path: "Tenant",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
+ Mandatory: true,
+ Layout: time.RFC3339},
+ {Tag: "ID",
+ Path: "ID",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
+ Mandatory: true,
+ Layout: time.RFC3339},
+ {Tag: "FilterIDs",
+ Path: "FilterIDs",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Weights",
+ Path: "Weights",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.3", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "TTL",
+ Path: "TTL",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.4", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Type",
+ Path: "Type",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.5", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "AddressPool",
+ Path: "AddressPool",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.6", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Allocation",
+ Path: "Allocation",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.7", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Stored",
+ Path: "Stored",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.8", utils.InfieldSep),
+ Layout: time.RFC3339},
+ },
+ },
{
Type: utils.MetaStats,
Filename: utils.StatsCsv,
@@ -3327,6 +3385,7 @@ func TestCgrCfgV1GetConfigSectionLoader(t *testing.T) {
utils.MetaFilters: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaAttributes: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaResources: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
+ utils.MetaIPs: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaStats: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaThresholds: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaRoutes: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
@@ -4615,7 +4674,7 @@ func TestV1GetConfigAsJSONGeneral(t *testing.T) {
func TestV1GetConfigAsJSONDataDB(t *testing.T) {
var reply string
- expected := `{"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/datadb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/datadb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false}}`
+ expected := `{"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ip_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/datadb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/datadb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false}}`
cfgCgr := NewDefaultCGRConfig()
if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Sections: []string{DataDBJSON}}, &reply); err != nil {
t.Error(err)
@@ -4637,7 +4696,7 @@ func TestV1GetConfigAsJSONTls(t *testing.T) {
func TestV1GetConfigAsJSONTCache(t *testing.T) {
var reply string
- expected := `{"caches":{"partitions":{"*account_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]}}`
+ expected := `{"caches":{"partitions":{"*account_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ip_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]}}`
cfgCgr := NewDefaultCGRConfig()
if err := cfgCgr.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Sections: []string{CacheJSON}}, &reply); err != nil {
t.Error(err)
@@ -4859,7 +4918,7 @@ func TestV1GetConfigAsJSONSureTax(t *testing.T) {
func TestV1GetConfigAsJSONLoaders(t *testing.T) {
var reply string
- expected := `{"loaders":[{"action":"*store","cache":{"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*attributes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*chargers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*stats":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"new_branch":true,"path":"Rules.Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Rules.Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Rules.Values","tag":"Values","type":"*variable","value":"~*req.4"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"new_branch":true,"path":"Attributes.FilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Attributes.Blockers","tag":"AttributeBlockers","type":"*variable","value":"~*req.6"},{"path":"Attributes.Path","tag":"Path","type":"*variable","value":"~*req.7"},{"path":"Attributes.Type","tag":"Type","type":"*variable","value":"~*req.8"},{"path":"Attributes.Value","tag":"Value","type":"*variable","value":"~*req.9"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.5"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"},{"new_branch":true,"path":"Metrics.MetricID","tag":"MetricIDs","type":"*variable","value":"~*req.10"},{"path":"Metrics.FilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.11"},{"path":"Metrics.Blockers","tag":"MetricBlockers","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"ActionProfileIDs","tag":"ActionProfileIDs","type":"*variable","value":"~*req.8"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.9"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatID","tag":"StatID","type":"*variable","value":"~*req.3"},{"path":"Metrics","tag":"Metrics","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"CorrelationType","tag":"CorrelationType","type":"*variable","value":"~*req.8"},{"path":"Tolerance","tag":"Tolerance","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.11"}],"file_name":"Trends.csv","flags":null,"type":"*trends"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatIDs","tag":"StatIDs","type":"*variable","value":"~*req.3"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.7"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.8"}],"file_name":"Rankings.csv","flags":null,"type":"*rankings"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"new_branch":true,"path":"Routes.ID","tag":"RouteID","type":"*variable","value":"~*req.7"},{"path":"Routes.FilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Routes.AccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.9"},{"path":"Routes.RateProfileIDs","tag":"RouteRateProfileIDs","type":"*variable","value":"~*req.10"},{"path":"Routes.ResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.11"},{"path":"Routes.StatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.12"},{"path":"Routes.Weights","tag":"RouteWeights","type":"*variable","value":"~*req.13"},{"path":"Routes.Blockers","tag":"RouteBlockers","type":"*variable","value":"~*req.14"},{"path":"Routes.RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.5"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.4"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.5"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.6"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].FilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].ActivationTimes","tag":"RateActivationTimes","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Weights","tag":"RateWeights","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Blocker","tag":"RateBlocker","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.7:"],"new_branch":true,"path":"Rates[\u003c~*req.7\u003e].IntervalRates.IntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.FixedFee","tag":"RateFixedFee","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.RecurrentFee","tag":"RateRecurrentFee","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Unit","tag":"RateUnit","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Increment","tag":"RateIncrement","type":"*variable","value":"~*req.16"}],"file_name":"Rates.csv","flags":null,"type":"*rate_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.5"},{"path":"Targets[\u003c~*req.6\u003e]","tag":"TargetIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].FilterIDs","tag":"ActionFilterIDs","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].TTL","tag":"ActionTTL","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Type","tag":"ActionType","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Opts","tag":"ActionOpts","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.8:"],"new_branch":true,"path":"Actions[\u003c~*req.8\u003e].Diktats.Path","tag":"ActionPath","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Diktats.Value","tag":"ActionValue","type":"*variable","value":"~*req.14"}],"file_name":"Actions.csv","flags":null,"type":"*action_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Opts","tag":"Opts","type":"*variable","value":"~*req.5"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].FilterIDs","tag":"BalanceFilterIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Weights","tag":"BalanceWeights","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Blockers","tag":"BalanceBlockers","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Type","tag":"BalanceType","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Units","tag":"BalanceUnits","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].UnitFactors","tag":"BalanceUnitFactors","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Opts","tag":"BalanceOpts","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].CostIncrements","tag":"BalanceCostIncrements","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].AttributeIDs","tag":"BalanceAttributeIDs","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].RateProfileIDs","tag":"BalanceRateProfileIDs","type":"*variable","value":"~*req.16"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.17"}],"file_name":"Accounts.csv","flags":null,"type":"*accounts"}],"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","opts":{"*cache":"","*forceLock":false,"*stopOnError":false,"*withIndex":true},"run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}]}`
+ expected := `{"loaders":[{"action":"*store","cache":{"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*attributes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*chargers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*stats":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"new_branch":true,"path":"Rules.Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Rules.Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Rules.Values","tag":"Values","type":"*variable","value":"~*req.4"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"new_branch":true,"path":"Attributes.FilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Attributes.Blockers","tag":"AttributeBlockers","type":"*variable","value":"~*req.6"},{"path":"Attributes.Path","tag":"Path","type":"*variable","value":"~*req.7"},{"path":"Attributes.Type","tag":"Type","type":"*variable","value":"~*req.8"},{"path":"Attributes.Value","tag":"Value","type":"*variable","value":"~*req.9"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.5"},{"path":"AddressPool","tag":"AddressPool","type":"*variable","value":"~*req.6"},{"path":"Allocation","tag":"Allocation","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"}],"file_name":"IPs.csv","flags":null,"type":"*ips"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.5"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"},{"new_branch":true,"path":"Metrics.MetricID","tag":"MetricIDs","type":"*variable","value":"~*req.10"},{"path":"Metrics.FilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.11"},{"path":"Metrics.Blockers","tag":"MetricBlockers","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"ActionProfileIDs","tag":"ActionProfileIDs","type":"*variable","value":"~*req.8"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.9"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatID","tag":"StatID","type":"*variable","value":"~*req.3"},{"path":"Metrics","tag":"Metrics","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"CorrelationType","tag":"CorrelationType","type":"*variable","value":"~*req.8"},{"path":"Tolerance","tag":"Tolerance","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.11"}],"file_name":"Trends.csv","flags":null,"type":"*trends"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatIDs","tag":"StatIDs","type":"*variable","value":"~*req.3"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.7"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.8"}],"file_name":"Rankings.csv","flags":null,"type":"*rankings"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"new_branch":true,"path":"Routes.ID","tag":"RouteID","type":"*variable","value":"~*req.7"},{"path":"Routes.FilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Routes.AccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.9"},{"path":"Routes.RateProfileIDs","tag":"RouteRateProfileIDs","type":"*variable","value":"~*req.10"},{"path":"Routes.ResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.11"},{"path":"Routes.StatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.12"},{"path":"Routes.Weights","tag":"RouteWeights","type":"*variable","value":"~*req.13"},{"path":"Routes.Blockers","tag":"RouteBlockers","type":"*variable","value":"~*req.14"},{"path":"Routes.RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.5"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.4"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.5"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.6"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].FilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].ActivationTimes","tag":"RateActivationTimes","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Weights","tag":"RateWeights","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Blocker","tag":"RateBlocker","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.7:"],"new_branch":true,"path":"Rates[\u003c~*req.7\u003e].IntervalRates.IntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.FixedFee","tag":"RateFixedFee","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.RecurrentFee","tag":"RateRecurrentFee","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Unit","tag":"RateUnit","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Increment","tag":"RateIncrement","type":"*variable","value":"~*req.16"}],"file_name":"Rates.csv","flags":null,"type":"*rate_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.5"},{"path":"Targets[\u003c~*req.6\u003e]","tag":"TargetIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].FilterIDs","tag":"ActionFilterIDs","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].TTL","tag":"ActionTTL","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Type","tag":"ActionType","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Opts","tag":"ActionOpts","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.8:"],"new_branch":true,"path":"Actions[\u003c~*req.8\u003e].Diktats.Path","tag":"ActionPath","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Diktats.Value","tag":"ActionValue","type":"*variable","value":"~*req.14"}],"file_name":"Actions.csv","flags":null,"type":"*action_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Opts","tag":"Opts","type":"*variable","value":"~*req.5"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].FilterIDs","tag":"BalanceFilterIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Weights","tag":"BalanceWeights","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Blockers","tag":"BalanceBlockers","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Type","tag":"BalanceType","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Units","tag":"BalanceUnits","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].UnitFactors","tag":"BalanceUnitFactors","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Opts","tag":"BalanceOpts","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].CostIncrements","tag":"BalanceCostIncrements","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].AttributeIDs","tag":"BalanceAttributeIDs","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].RateProfileIDs","tag":"BalanceRateProfileIDs","type":"*variable","value":"~*req.16"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.17"}],"file_name":"Accounts.csv","flags":null,"type":"*accounts"}],"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","opts":{"*cache":"","*forceLock":false,"*stopOnError":false,"*withIndex":true},"run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}]}`
cgrCfg := NewDefaultCGRConfig()
if err := cgrCfg.V1GetConfigAsJSON(context.Background(), &SectionWithAPIOpts{Sections: []string{LoaderSJSON}}, &reply); err != nil {
t.Error(err)
@@ -5076,7 +5135,7 @@ func TestV1GetConfigAsJSONAllConfig(t *testing.T) {
}
}`
var reply string
- expected := `{"accounts":{"attributes_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"max_iterations":1000,"max_usage":"259200000000000","nested_fields":false,"notexists_indexed_fields":[],"opts":{"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*usage":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"rates_conns":[],"suffix_indexed_fields":[],"thresholds_conns":[]},"actions":{"accounts_conns":[],"cdrs_conns":[],"dynaprepaid_actionprofile":[],"ees_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*posterAttempts":[{"FilterIDs":null,"Tenant":""}],"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"stats_conns":[],"suffix_indexed_fields":[],"tenants":[],"thresholds_conns":[]},"admins":{"actions_conns":[],"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false},"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","ees_conns":[],"enabled":false,"index_type":"*scorch","opts":{"*exporterIDs":[]},"ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"accounts_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*processRuns":[{"FilterIDs":null,"Tenant":""}],"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*profileRuns":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"accounts_conns":[],"actions_conns":[],"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":null,"opts":{"*accounts":[{"FilterIDs":null,"Tenant":""}],"*attributes":[{"FilterIDs":null,"Tenant":""}],"*chargers":[{"FilterIDs":null,"Tenant":""}],"*ees":[{"FilterIDs":null,"Tenant":""}],"*rates":[{"FilterIDs":null,"Tenant":""}],"*refund":[{"FilterIDs":null,"Tenant":""}],"*rerate":[{"FilterIDs":null,"Tenant":""}],"*stats":[{"FilterIDs":null,"Tenant":""}],"*store":[{"FilterIDs":null,"Tenant":""}],"*thresholds":[{"FilterIDs":null,"Tenant":""}]},"rates_conns":[],"session_cost_retries":5,"stats_conns":[],"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"config_db":{"db_host":"","db_name":"","db_password":"","db_port":0,"db_type":"*internal","db_user":"","opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/configdb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/configdb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"}},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","ees_conns":[],"shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/datadb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/datadb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*fileCSV":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"blocker":false,"concurrent_requests":0,"efs_conns":["*internal"],"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"efs":{"enabled":false,"failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","poster_attempts":3},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","start_delay":"0","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"accounts_conns":[],"rankings_conns":[],"resources_conns":[],"stats_conns":[],"trends_conns":[]},"freeswitch_agent":{"active_session_delimiter":",","create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5,"reply_timeout":"1m0s"}],"extra_fields":[],"low_balance_ann_file":"","max_wait_connection":"2s","request_processors":[],"sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"caching_delay":"0","connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","decimal_max_scale":0,"decimal_min_scale":0,"decimal_precision":0,"decimal_rounding_mode":"*toNearestEven","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","locking_timeout":"0","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","opts":{"*exporterIDs":[]},"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTLSVerification":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","pprof_path":"/debug/pprof/","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"janus_agent":{"enabled":false,"janus_conns":[{"address":"127.0.0.1:8088","admin_address":"localhost:7188","admin_password":"","type":"*ws"}],"request_processors":[],"sessions_conns":["*internal"],"url":"/janus"},"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"actions_conns":["*localhost"],"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","tpid":""},"loaders":[{"action":"*store","cache":{"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*attributes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*chargers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*stats":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"new_branch":true,"path":"Rules.Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Rules.Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Rules.Values","tag":"Values","type":"*variable","value":"~*req.4"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"new_branch":true,"path":"Attributes.FilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Attributes.Blockers","tag":"AttributeBlockers","type":"*variable","value":"~*req.6"},{"path":"Attributes.Path","tag":"Path","type":"*variable","value":"~*req.7"},{"path":"Attributes.Type","tag":"Type","type":"*variable","value":"~*req.8"},{"path":"Attributes.Value","tag":"Value","type":"*variable","value":"~*req.9"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.5"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"},{"new_branch":true,"path":"Metrics.MetricID","tag":"MetricIDs","type":"*variable","value":"~*req.10"},{"path":"Metrics.FilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.11"},{"path":"Metrics.Blockers","tag":"MetricBlockers","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"ActionProfileIDs","tag":"ActionProfileIDs","type":"*variable","value":"~*req.8"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.9"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatID","tag":"StatID","type":"*variable","value":"~*req.3"},{"path":"Metrics","tag":"Metrics","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"CorrelationType","tag":"CorrelationType","type":"*variable","value":"~*req.8"},{"path":"Tolerance","tag":"Tolerance","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.11"}],"file_name":"Trends.csv","flags":null,"type":"*trends"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatIDs","tag":"StatIDs","type":"*variable","value":"~*req.3"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.7"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.8"}],"file_name":"Rankings.csv","flags":null,"type":"*rankings"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"new_branch":true,"path":"Routes.ID","tag":"RouteID","type":"*variable","value":"~*req.7"},{"path":"Routes.FilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Routes.AccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.9"},{"path":"Routes.RateProfileIDs","tag":"RouteRateProfileIDs","type":"*variable","value":"~*req.10"},{"path":"Routes.ResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.11"},{"path":"Routes.StatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.12"},{"path":"Routes.Weights","tag":"RouteWeights","type":"*variable","value":"~*req.13"},{"path":"Routes.Blockers","tag":"RouteBlockers","type":"*variable","value":"~*req.14"},{"path":"Routes.RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.5"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.4"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.5"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.6"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].FilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].ActivationTimes","tag":"RateActivationTimes","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Weights","tag":"RateWeights","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Blocker","tag":"RateBlocker","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.7:"],"new_branch":true,"path":"Rates[\u003c~*req.7\u003e].IntervalRates.IntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.FixedFee","tag":"RateFixedFee","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.RecurrentFee","tag":"RateRecurrentFee","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Unit","tag":"RateUnit","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Increment","tag":"RateIncrement","type":"*variable","value":"~*req.16"}],"file_name":"Rates.csv","flags":null,"type":"*rate_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.5"},{"path":"Targets[\u003c~*req.6\u003e]","tag":"TargetIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].FilterIDs","tag":"ActionFilterIDs","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].TTL","tag":"ActionTTL","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Type","tag":"ActionType","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Opts","tag":"ActionOpts","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.8:"],"new_branch":true,"path":"Actions[\u003c~*req.8\u003e].Diktats.Path","tag":"ActionPath","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Diktats.Value","tag":"ActionValue","type":"*variable","value":"~*req.14"}],"file_name":"Actions.csv","flags":null,"type":"*action_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Opts","tag":"Opts","type":"*variable","value":"~*req.5"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].FilterIDs","tag":"BalanceFilterIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Weights","tag":"BalanceWeights","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Blockers","tag":"BalanceBlockers","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Type","tag":"BalanceType","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Units","tag":"BalanceUnits","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].UnitFactors","tag":"BalanceUnitFactors","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Opts","tag":"BalanceOpts","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].CostIncrements","tag":"BalanceCostIncrements","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].AttributeIDs","tag":"BalanceAttributeIDs","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].RateProfileIDs","tag":"BalanceRateProfileIDs","type":"*variable","value":"~*req.16"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.17"}],"file_name":"Accounts.csv","flags":null,"type":"*accounts"}],"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","opts":{"*cache":"","*forceLock":false,"*stopOnError":false,"*withIndex":true},"run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"logger":{"efs_conns":["*internal"],"level":6,"opts":{"failed_posts_dir":"/var/spool/cgrates/failed_posts","kafka_attempts":1,"kafka_conn":"","kafka_topic":""},"type":"*syslog"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"*redis","out_datadb_user":"cgrates","users_filters":null},"prometheus_agent":{"collect_go_metrics":false,"collect_process_metrics":false,"cores_conns":[],"enabled":false,"path":"/prometheus","stat_queue_ids":null,"stats_conns":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rankings":{"ees_conns":[],"ees_exporter_ids":null,"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","thresholds_conns":[]},"rates":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*intervalStart":[{"FilterIDs":null,"Tenant":""}],"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*startTime":[{"FilterIDs":null,"Tenant":""}],"*usage":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"rate_exists_indexed_fields":[],"rate_indexed_selects":true,"rate_nested_fields":false,"rate_notexists_indexed_fields":[],"rate_prefix_indexed_fields":[],"rate_suffix_indexed_fields":[],"suffix_indexed_fields":[],"verbosity":1000},"registrarc":{"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*units":[{"FilterIDs":null,"Tenant":""}],"*usageID":[{"FilterIDs":null,"Tenant":""}],"*usageTTL":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"accounts_conns":[],"attributes_conns":[],"default_ratio":1,"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*context":[{"FilterIDs":null,"Tenant":""}],"*ignoreErrors":[{"FilterIDs":null,"Tenant":""}],"*limit":[],"*maxCost":[{"Tenant":"","Value":""}],"*maxItems":[],"*offset":[],"*profileCount":[{"FilterIDs":null,"Tenant":""}],"*usage":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"rates_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"sentrypeer":{"audience":"https://sentrypeer.com/api","client_id":"","client_secret":"","grant_type":"client_credentials","ips_url":"https://sentrypeer.com/api/ip-addresses","numbers_url":"https://sentrypeer.com/api/phone-numbers","token_url":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"accounts_conns":[],"actions_conns":[],"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","opts":{"*accounts":[{"FilterIDs":null,"Tenant":""}],"*accountsForceUsage":[],"*attributes":[{"FilterIDs":null,"Tenant":""}],"*attributesDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*blockerError":[{"FilterIDs":null,"Tenant":""}],"*cdrs":[{"FilterIDs":null,"Tenant":""}],"*cdrsDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*chargeable":[{"FilterIDs":null,"Tenant":""}],"*chargers":[{"FilterIDs":null,"Tenant":""}],"*debitInterval":[{"FilterIDs":null,"Tenant":""}],"*forceUsage":[],"*initiate":[{"FilterIDs":null,"Tenant":""}],"*maxUsage":[{"FilterIDs":null,"Tenant":""}],"*message":[{"FilterIDs":null,"Tenant":""}],"*originID":[],"*resources":[{"FilterIDs":null,"Tenant":""}],"*resourcesAllocate":[{"FilterIDs":null,"Tenant":""}],"*resourcesAuthorize":[{"FilterIDs":null,"Tenant":""}],"*resourcesDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*resourcesRelease":[{"FilterIDs":null,"Tenant":""}],"*routes":[{"FilterIDs":null,"Tenant":""}],"*routesDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*stats":[{"FilterIDs":null,"Tenant":""}],"*statsDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*terminate":[{"FilterIDs":null,"Tenant":""}],"*thresholds":[{"FilterIDs":null,"Tenant":""}],"*thresholdsDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*ttl":[{"FilterIDs":null,"Tenant":""}],"*ttlLastUsage":[],"*ttlLastUsed":[],"*ttlMaxDelay":[{"FilterIDs":null,"Tenant":""}],"*ttlUsage":[],"*update":[{"FilterIDs":null,"Tenant":""}]},"rates_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"session_indexes":[],"stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":"1s","sessions_conns":["*internal"],"timezone":""},"stats":{"ees_conns":[],"ees_exporter_ids":null,"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*roundingDecimals":[]},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"CGRateS.org","db_port":3306,"db_type":"**mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/stordb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/stordb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","sqlConnMaxLifetime":"0s","sqlLogLevel":3,"sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*opts.*originID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*fsa":[{"path":"*cgreq.ToR","tag":"ToR","type":"*constant","value":"*voice"},{"path":"*cgreq.PDD","tag":"PDD","type":"*composed","value":"~*req.variable_progress_mediamsec;ms"},{"path":"*cgreq.ACD","tag":"ACD","type":"*composed","value":"~*req.variable_cdr_acd;s"},{"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.Unique-ID"},{"path":"*opts.*originID","tag":"*originID","type":"*variable","value":"~*req.Unique-ID"},{"path":"*cgreq.OriginHost","tag":"OriginHost","type":"*variable","value":"~*req.variable_cgr_originhost"},{"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.Caller-Username"},{"path":"*cgreq.Source","tag":"Source","type":"*composed","value":"FS_;~*req.Event-Name"},{"filters":["*string:*req.variable_process_cdr:false"],"path":"*cgreq.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"filters":["*string:*req.Caller-Dialplan:inline"],"path":"*cgreq.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"filters":["*exists:*cgreq.RequestType:"],"path":"*cgreq.RequestType","tag":"RequestType","type":"*constant","value":"*prepaid"},{"path":"*cgreq.Tenant","tag":"Tenant","type":"*constant","value":"cgrates.org"},{"path":"*cgreq.Category","tag":"Category","type":"*constant","value":"call"},{"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.Caller-Username"},{"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.Caller-Destination-Number"},{"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.Caller-Channel-Created-Time"},{"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.Caller-Channel-Answered-Time"},{"path":"*cgreq.Usage","tag":"Usage","type":"*composed","value":"~*req.variable_billsec;s"},{"path":"*cgreq.Route","tag":"Route","type":"*variable","value":"~*req.variable_cgr_route"},{"path":"*cgreq.Cost","tag":"Cost","type":"*constant","value":"-1.0"},{"filters":["*notempty:*req.Hangup-Cause:"],"path":"*cgreq.DisconnectCause","tag":"DisconnectCause","type":"*variable","value":"~*req.Hangup-Cause"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"actions_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4},"tpes":{"enabled":false},"trends":{"ees_conns":[],"ees_exporter_ids":null,"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","store_uncompressed_limit":0,"thresholds_conns":[]}}`
+ expected := `{"accounts":{"attributes_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"max_iterations":1000,"max_usage":"259200000000000","nested_fields":false,"notexists_indexed_fields":[],"opts":{"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*usage":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"rates_conns":[],"suffix_indexed_fields":[],"thresholds_conns":[]},"actions":{"accounts_conns":[],"cdrs_conns":[],"dynaprepaid_actionprofile":[],"ees_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*posterAttempts":[{"FilterIDs":null,"Tenant":""}],"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"stats_conns":[],"suffix_indexed_fields":[],"tenants":[],"thresholds_conns":[]},"admins":{"actions_conns":[],"attributes_conns":[],"caches_conns":["*internal"],"ees_conns":[],"enabled":false},"analyzers":{"cleanup_interval":"1h0m0s","db_path":"/var/spool/cgrates/analyzers","ees_conns":[],"enabled":false,"index_type":"*scorch","opts":{"*exporterIDs":[]},"ttl":"24h0m0s"},"apiban":{"enabled":false,"keys":[]},"asterisk_agent":{"asterisk_conns":[{"address":"127.0.0.1:8088","alias":"","connect_attempts":3,"max_reconnect_interval":"0s","password":"CGRateS.org","reconnects":5,"user":"cgrates"}],"create_cdr":false,"enabled":false,"sessions_conns":["*birpc_internal"]},"attributes":{"accounts_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*processRuns":[{"FilterIDs":null,"Tenant":""}],"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*profileRuns":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"caches":{"partitions":{"*account_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*apiban":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2m0s"},"*attribute_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*caps_events":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*cdr_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10m0s"},"*charger_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*closed_sessions":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*diameter_messages":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*event_charges":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"10s"},"*event_ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*event_resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ip_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*replication_hosts":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_connections":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*rpc_responses":{"limit":0,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"2s"},"*sentrypeer":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":true,"ttl":"24h0m0s"},"*stat_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*stir":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"},"*threshold_filter_indexes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false},"*uch":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"3h0m0s"}},"remote_conns":[],"replication_conns":[]},"cdrs":{"accounts_conns":[],"actions_conns":[],"attributes_conns":[],"chargers_conns":[],"ees_conns":[],"enabled":false,"extra_fields":[],"online_cdr_exports":null,"opts":{"*accounts":[{"FilterIDs":null,"Tenant":""}],"*attributes":[{"FilterIDs":null,"Tenant":""}],"*chargers":[{"FilterIDs":null,"Tenant":""}],"*ees":[{"FilterIDs":null,"Tenant":""}],"*rates":[{"FilterIDs":null,"Tenant":""}],"*refund":[{"FilterIDs":null,"Tenant":""}],"*rerate":[{"FilterIDs":null,"Tenant":""}],"*stats":[{"FilterIDs":null,"Tenant":""}],"*store":[{"FilterIDs":null,"Tenant":""}],"*thresholds":[{"FilterIDs":null,"Tenant":""}]},"rates_conns":[],"session_cost_retries":5,"stats_conns":[],"thresholds_conns":[]},"chargers":{"attributes_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"prefix_indexed_fields":[],"suffix_indexed_fields":[]},"config_db":{"db_host":"","db_name":"","db_password":"","db_port":0,"db_type":"*internal","db_user":"","opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/configdb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/configdb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"}},"configs":{"enabled":false,"root_dir":"/var/spool/cgrates/configs","url":"/configs/"},"cores":{"caps":0,"caps_stats_interval":"0","caps_strategy":"*busy","ees_conns":[],"shutdown_timeout":"1s"},"data_db":{"db_host":"127.0.0.1","db_name":"10","db_password":"","db_port":6379,"db_type":"*redis","db_user":"cgrates","items":{"*account_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*accounts":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*action_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*actions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*attribute_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*charger_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*filters":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ip_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ip_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ips":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*load_ids":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*ranking_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rankings":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profile_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*rate_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resource_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*resources":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*reverse_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*route_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*stat_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueue_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*statqueues":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_filter_indexes":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*threshold_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*thresholds":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trend_profiles":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*trends":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false},"*versions":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/datadb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/datadb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"remote_conn_id":"","remote_conns":[],"replication_cache":"","replication_conns":[],"replication_filtered":false},"diameter_agent":{"asr_template":"","dictionaries_path":"/usr/share/cgrates/diameter/dict/","enabled":false,"forced_disconnect":"*none","listen":"127.0.0.1:3868","listen_net":"tcp","origin_host":"CGR-DA","origin_realm":"cgrates.org","product_name":"CGRateS","rar_template":"","request_processors":[],"sessions_conns":["*birpc_internal"],"synced_conn_requests":false,"vendor_id":0},"dns_agent":{"enabled":false,"listeners":[{"address":"127.0.0.1:53","network":"udp"}],"request_processors":[],"sessions_conns":["*internal"],"timezone":""},"ees":{"attributes_conns":[],"cache":{"*fileCSV":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"enabled":false,"exporters":[{"attempts":1,"attribute_context":"","attribute_ids":[],"blocker":false,"concurrent_requests":0,"efs_conns":["*internal"],"export_path":"/var/spool/cgrates/ees","failed_posts_dir":"/var/spool/cgrates/failed_posts","fields":[],"filters":[],"flags":[],"id":"*default","opts":{},"synchronous":false,"timezone":"","type":"*none"}]},"efs":{"enabled":false,"failed_posts_dir":"/var/spool/cgrates/failed_posts","failed_posts_ttl":"5s","poster_attempts":3},"ers":{"enabled":false,"partial_cache_ttl":"1s","readers":[{"cache_dump_fields":[],"concurrent_requests":1024,"fields":[{"mandatory":true,"path":"*cgreq.ToR","tag":"ToR","type":"*variable","value":"~*req.2"},{"mandatory":true,"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.3"},{"mandatory":true,"path":"*cgreq.RequestType","tag":"RequestType","type":"*variable","value":"~*req.4"},{"mandatory":true,"path":"*cgreq.Tenant","tag":"Tenant","type":"*variable","value":"~*req.6"},{"mandatory":true,"path":"*cgreq.Category","tag":"Category","type":"*variable","value":"~*req.7"},{"mandatory":true,"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.8"},{"mandatory":true,"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.9"},{"mandatory":true,"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.10"},{"mandatory":true,"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.11"},{"mandatory":true,"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.12"},{"mandatory":true,"path":"*cgreq.Usage","tag":"Usage","type":"*variable","value":"~*req.13"}],"filters":[],"flags":[],"id":"*default","max_reconnect_interval":"5m0s","opts":{"csvFieldSeparator":",","csvHeaderDefineChar":":","csvRowLength":0,"natsSubject":"cgrates_cdrs","partialCacheAction":"*none","partialOrderField":"~*req.AnswerTime"},"partial_commit_fields":[],"processed_path":"/var/spool/cgrates/ers/out","reconnects":-1,"run_delay":"0","source_path":"/var/spool/cgrates/ers/in","start_delay":"0","tenant":"","timezone":"","type":"*none"}],"sessions_conns":["*internal"]},"filters":{"accounts_conns":[],"rankings_conns":[],"resources_conns":[],"stats_conns":[],"trends_conns":[]},"freeswitch_agent":{"active_session_delimiter":",","create_cdr":false,"empty_balance_ann_file":"","empty_balance_context":"","enabled":false,"event_socket_conns":[{"address":"127.0.0.1:8021","alias":"127.0.0.1:8021","max_reconnect_interval":"0s","password":"ClueCon","reconnects":5,"reply_timeout":"1m0s"}],"extra_fields":[],"low_balance_ann_file":"","max_wait_connection":"2s","request_processors":[],"sessions_conns":["*birpc_internal"],"subscribe_park":true},"general":{"caching_delay":"0","connect_attempts":5,"connect_timeout":"1s","dbdata_encoding":"*msgpack","decimal_max_scale":0,"decimal_min_scale":0,"decimal_precision":0,"decimal_rounding_mode":"*toNearestEven","default_caching":"*reload","default_category":"call","default_request_type":"*rated","default_tenant":"cgrates.org","default_timezone":"Local","digest_equal":":","digest_separator":",","locking_timeout":"0","max_parallel_conns":100,"max_reconnect_interval":"0","node_id":"ENGINE1","opts":{"*exporterIDs":[]},"reconnects":-1,"reply_timeout":"2s","rounding_decimals":5,"tpexport_dir":"/var/spool/cgrates/tpe"},"http":{"auth_users":{},"client_opts":{"dialFallbackDelay":"300ms","dialKeepAlive":"30s","dialTimeout":"30s","disableCompression":false,"disableKeepAlives":false,"expectContinueTimeout":"0s","forceAttemptHttp2":true,"idleConnTimeout":"1m30s","maxConnsPerHost":0,"maxIdleConns":100,"maxIdleConnsPerHost":2,"responseHeaderTimeout":"0s","skipTLSVerification":false,"tlsHandshakeTimeout":"10s"},"freeswitch_cdrs_url":"/freeswitch_json","http_cdrs":"/cdr_http","json_rpc_url":"/jsonrpc","pprof_path":"/debug/pprof/","registrars_url":"/registrar","use_basic_auth":false,"ws_url":"/ws"},"http_agent":[],"ips":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":null,"opts":{"*ttl":[{"FilterIDs":null,"Tenant":""}],"*units":[{"FilterIDs":null,"Tenant":""}],"*usageID":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"store_interval":"0s","string_indexed_fields":null,"suffix_indexed_fields":[]},"janus_agent":{"enabled":false,"janus_conns":[{"address":"127.0.0.1:8088","admin_address":"localhost:7188","admin_password":"","type":"*ws"}],"request_processors":[],"sessions_conns":["*internal"],"url":"/janus"},"kamailio_agent":{"create_cdr":false,"enabled":false,"evapi_conns":[{"address":"127.0.0.1:8448","alias":"","max_reconnect_interval":"0s","reconnects":5}],"sessions_conns":["*birpc_internal"],"timezone":""},"listen":{"http":"127.0.0.1:2080","http_tls":"127.0.0.1:2280","rpc_gob":"127.0.0.1:2013","rpc_gob_tls":"127.0.0.1:2023","rpc_json":"127.0.0.1:2012","rpc_json_tls":"127.0.0.1:2022"},"loader":{"actions_conns":["*localhost"],"caches_conns":["*localhost"],"data_path":"./","disable_reverse":false,"field_separator":",","gapi_credentials":".gapi/credentials.json","gapi_token":".gapi/token.json","tpid":""},"loaders":[{"action":"*store","cache":{"*accounts":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*action_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*attributes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*chargers":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*filters":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*ips":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rankings":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*rate_profiles":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*resources":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*routes":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*stats":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*thresholds":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"},"*trends":{"limit":-1,"precache":false,"remote":false,"replicate":false,"static_ttl":false,"ttl":"5s"}},"caches_conns":["*internal"],"data":[{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"new_branch":true,"path":"Rules.Type","tag":"Type","type":"*variable","value":"~*req.2"},{"path":"Rules.Element","tag":"Element","type":"*variable","value":"~*req.3"},{"path":"Rules.Values","tag":"Values","type":"*variable","value":"~*req.4"}],"file_name":"Filters.csv","flags":null,"type":"*filters"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"TenantID","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ProfileID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"new_branch":true,"path":"Attributes.FilterIDs","tag":"AttributeFilterIDs","type":"*variable","value":"~*req.5"},{"path":"Attributes.Blockers","tag":"AttributeBlockers","type":"*variable","value":"~*req.6"},{"path":"Attributes.Path","tag":"Path","type":"*variable","value":"~*req.7"},{"path":"Attributes.Type","tag":"Type","type":"*variable","value":"~*req.8"},{"path":"Attributes.Value","tag":"Value","type":"*variable","value":"~*req.9"}],"file_name":"Attributes.csv","flags":null,"type":"*attributes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"UsageTTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Limit","tag":"Limit","type":"*variable","value":"~*req.5"},{"path":"AllocationMessage","tag":"AllocationMessage","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"}],"file_name":"Resources.csv","flags":null,"type":"*resources"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.4"},{"path":"Type","tag":"Type","type":"*variable","value":"~*req.5"},{"path":"AddressPool","tag":"AddressPool","type":"*variable","value":"~*req.6"},{"path":"Allocation","tag":"Allocation","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"}],"file_name":"IPs.csv","flags":null,"type":"*ips"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.5"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.8"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.9"},{"new_branch":true,"path":"Metrics.MetricID","tag":"MetricIDs","type":"*variable","value":"~*req.10"},{"path":"Metrics.FilterIDs","tag":"MetricFilterIDs","type":"*variable","value":"~*req.11"},{"path":"Metrics.Blockers","tag":"MetricBlockers","type":"*variable","value":"~*req.12"}],"file_name":"Stats.csv","flags":null,"type":"*stats"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MaxHits","tag":"MaxHits","type":"*variable","value":"~*req.4"},{"path":"MinHits","tag":"MinHits","type":"*variable","value":"~*req.5"},{"path":"MinSleep","tag":"MinSleep","type":"*variable","value":"~*req.6"},{"path":"Blocker","tag":"Blocker","type":"*variable","value":"~*req.7"},{"path":"ActionProfileIDs","tag":"ActionProfileIDs","type":"*variable","value":"~*req.8"},{"path":"Async","tag":"Async","type":"*variable","value":"~*req.9"}],"file_name":"Thresholds.csv","flags":null,"type":"*thresholds"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatID","tag":"StatID","type":"*variable","value":"~*req.3"},{"path":"Metrics","tag":"Metrics","type":"*variable","value":"~*req.4"},{"path":"TTL","tag":"TTL","type":"*variable","value":"~*req.5"},{"path":"QueueLength","tag":"QueueLength","type":"*variable","value":"~*req.6"},{"path":"MinItems","tag":"MinItems","type":"*variable","value":"~*req.7"},{"path":"CorrelationType","tag":"CorrelationType","type":"*variable","value":"~*req.8"},{"path":"Tolerance","tag":"Tolerance","type":"*variable","value":"~*req.9"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.10"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.11"}],"file_name":"Trends.csv","flags":null,"type":"*trends"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.2"},{"path":"StatIDs","tag":"StatIDs","type":"*variable","value":"~*req.3"},{"path":"MetricIDs","tag":"MetricIDs","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"path":"Stored","tag":"Stored","type":"*variable","value":"~*req.7"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.8"}],"file_name":"Rankings.csv","flags":null,"type":"*rankings"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Sorting","tag":"Sorting","type":"*variable","value":"~*req.5"},{"path":"SortingParameters","tag":"SortingParameters","type":"*variable","value":"~*req.6"},{"new_branch":true,"path":"Routes.ID","tag":"RouteID","type":"*variable","value":"~*req.7"},{"path":"Routes.FilterIDs","tag":"RouteFilterIDs","type":"*variable","value":"~*req.8"},{"path":"Routes.AccountIDs","tag":"RouteAccountIDs","type":"*variable","value":"~*req.9"},{"path":"Routes.RateProfileIDs","tag":"RouteRateProfileIDs","type":"*variable","value":"~*req.10"},{"path":"Routes.ResourceIDs","tag":"RouteResourceIDs","type":"*variable","value":"~*req.11"},{"path":"Routes.StatIDs","tag":"RouteStatIDs","type":"*variable","value":"~*req.12"},{"path":"Routes.Weights","tag":"RouteWeights","type":"*variable","value":"~*req.13"},{"path":"Routes.Blockers","tag":"RouteBlockers","type":"*variable","value":"~*req.14"},{"path":"Routes.RouteParameters","tag":"RouteParameters","type":"*variable","value":"~*req.15"}],"file_name":"Routes.csv","flags":null,"type":"*routes"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"RunID","tag":"RunID","type":"*variable","value":"~*req.5"},{"path":"AttributeIDs","tag":"AttributeIDs","type":"*variable","value":"~*req.6"}],"file_name":"Chargers.csv","flags":null,"type":"*chargers"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"MinCost","tag":"MinCost","type":"*variable","value":"~*req.4"},{"path":"MaxCost","tag":"MaxCost","type":"*variable","value":"~*req.5"},{"path":"MaxCostStrategy","tag":"MaxCostStrategy","type":"*variable","value":"~*req.6"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].FilterIDs","tag":"RateFilterIDs","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].ActivationTimes","tag":"RateActivationTimes","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Weights","tag":"RateWeights","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].Blocker","tag":"RateBlocker","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.7:"],"new_branch":true,"path":"Rates[\u003c~*req.7\u003e].IntervalRates.IntervalStart","tag":"RateIntervalStart","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.FixedFee","tag":"RateFixedFee","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.RecurrentFee","tag":"RateRecurrentFee","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Unit","tag":"RateUnit","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.7:"],"path":"Rates[\u003c~*req.7\u003e].IntervalRates.Increment","tag":"RateIncrement","type":"*variable","value":"~*req.16"}],"file_name":"Rates.csv","flags":null,"type":"*rate_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Schedule","tag":"Schedule","type":"*variable","value":"~*req.5"},{"path":"Targets[\u003c~*req.6\u003e]","tag":"TargetIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].FilterIDs","tag":"ActionFilterIDs","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].TTL","tag":"ActionTTL","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Type","tag":"ActionType","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Opts","tag":"ActionOpts","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.8:"],"new_branch":true,"path":"Actions[\u003c~*req.8\u003e].Diktats.Path","tag":"ActionPath","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.8:"],"path":"Actions[\u003c~*req.8\u003e].Diktats.Value","tag":"ActionValue","type":"*variable","value":"~*req.14"}],"file_name":"Actions.csv","flags":null,"type":"*action_profiles"},{"fields":[{"mandatory":true,"path":"Tenant","tag":"Tenant","type":"*variable","value":"~*req.0"},{"mandatory":true,"path":"ID","tag":"ID","type":"*variable","value":"~*req.1"},{"path":"FilterIDs","tag":"FilterIDs","type":"*variable","value":"~*req.2"},{"path":"Weights","tag":"Weights","type":"*variable","value":"~*req.3"},{"path":"Blockers","tag":"Blockers","type":"*variable","value":"~*req.4"},{"path":"Opts","tag":"Opts","type":"*variable","value":"~*req.5"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].FilterIDs","tag":"BalanceFilterIDs","type":"*variable","value":"~*req.7"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Weights","tag":"BalanceWeights","type":"*variable","value":"~*req.8"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Blockers","tag":"BalanceBlockers","type":"*variable","value":"~*req.9"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Type","tag":"BalanceType","type":"*variable","value":"~*req.10"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Units","tag":"BalanceUnits","type":"*variable","value":"~*req.11"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].UnitFactors","tag":"BalanceUnitFactors","type":"*variable","value":"~*req.12"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].Opts","tag":"BalanceOpts","type":"*variable","value":"~*req.13"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].CostIncrements","tag":"BalanceCostIncrements","type":"*variable","value":"~*req.14"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].AttributeIDs","tag":"BalanceAttributeIDs","type":"*variable","value":"~*req.15"},{"filters":["*notempty:~*req.6:"],"path":"Balances[\u003c~*req.6\u003e].RateProfileIDs","tag":"BalanceRateProfileIDs","type":"*variable","value":"~*req.16"},{"path":"ThresholdIDs","tag":"ThresholdIDs","type":"*variable","value":"~*req.17"}],"file_name":"Accounts.csv","flags":null,"type":"*accounts"}],"enabled":false,"field_separator":",","id":"*default","lockfile_path":".cgr.lck","opts":{"*cache":"","*forceLock":false,"*stopOnError":false,"*withIndex":true},"run_delay":"0","tenant":"","tp_in_dir":"/var/spool/cgrates/loader/in","tp_out_dir":"/var/spool/cgrates/loader/out"}],"logger":{"efs_conns":["*internal"],"level":6,"opts":{"failed_posts_dir":"/var/spool/cgrates/failed_posts","kafka_attempts":1,"kafka_conn":"","kafka_topic":""},"type":"*syslog"},"migrator":{"out_datadb_encoding":"msgpack","out_datadb_host":"127.0.0.1","out_datadb_name":"10","out_datadb_opts":{"mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","redisCACertificate":"","redisClientCertificate":"","redisClientKey":"","redisCluster":false,"redisClusterOndownDelay":"0s","redisClusterSync":"5s","redisConnectAttempts":20,"redisConnectTimeout":"0s","redisMaxConns":10,"redisPoolPipelineLimit":0,"redisPoolPipelineWindow":"150µs","redisReadTimeout":"0s","redisSentinel":"","redisTLS":false,"redisWriteTimeout":"0s"},"out_datadb_password":"","out_datadb_port":"6379","out_datadb_type":"*redis","out_datadb_user":"cgrates","users_filters":null},"prometheus_agent":{"collect_go_metrics":false,"collect_process_metrics":false,"cores_conns":[],"enabled":false,"path":"/prometheus","stat_queue_ids":null,"stats_conns":[]},"radius_agent":{"client_dictionaries":{"*default":"/usr/share/cgrates/radius/dict/"},"client_secrets":{"*default":"CGRateS.org"},"enabled":false,"listen_acct":"127.0.0.1:1813","listen_auth":"127.0.0.1:1812","listen_net":"udp","request_processors":[],"sessions_conns":["*internal"]},"rankings":{"ees_conns":[],"ees_exporter_ids":null,"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","thresholds_conns":[]},"rates":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*intervalStart":[{"FilterIDs":null,"Tenant":""}],"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*startTime":[{"FilterIDs":null,"Tenant":""}],"*usage":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"rate_exists_indexed_fields":[],"rate_indexed_selects":true,"rate_nested_fields":false,"rate_notexists_indexed_fields":[],"rate_prefix_indexed_fields":[],"rate_suffix_indexed_fields":[],"suffix_indexed_fields":[],"verbosity":1000},"registrarc":{"rpc":{"hosts":[],"refresh_interval":"5m0s","registrars_conns":[]}},"resources":{"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*units":[{"FilterIDs":null,"Tenant":""}],"*usageID":[{"FilterIDs":null,"Tenant":""}],"*usageTTL":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[],"thresholds_conns":[]},"routes":{"accounts_conns":[],"attributes_conns":[],"default_ratio":1,"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*context":[{"FilterIDs":null,"Tenant":""}],"*ignoreErrors":[{"FilterIDs":null,"Tenant":""}],"*limit":[],"*maxCost":[{"Tenant":"","Value":""}],"*maxItems":[],"*offset":[],"*profileCount":[{"FilterIDs":null,"Tenant":""}],"*usage":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"rates_conns":[],"resources_conns":[],"stats_conns":[],"suffix_indexed_fields":[]},"rpc_conns":{"*bijson_localhost":{"conns":[{"address":"127.0.0.1:2014","transport":"*birpc_json"}],"poolSize":0,"strategy":"*first"},"*birpc_internal":{"conns":[{"address":"*birpc_internal","transport":""}],"poolSize":0,"strategy":"*first"},"*internal":{"conns":[{"address":"*internal","transport":""}],"poolSize":0,"strategy":"*first"},"*localhost":{"conns":[{"address":"127.0.0.1:2012","transport":"*json"}],"poolSize":0,"strategy":"*first"}},"sentrypeer":{"audience":"https://sentrypeer.com/api","client_id":"","client_secret":"","grant_type":"client_credentials","ips_url":"https://sentrypeer.com/api/ip-addresses","numbers_url":"https://sentrypeer.com/api/phone-numbers","token_url":"https://authz.sentrypeer.com/oauth/token"},"sessions":{"accounts_conns":[],"actions_conns":[],"alterable_fields":[],"attributes_conns":[],"cdrs_conns":[],"channel_sync_interval":"0","chargers_conns":[],"client_protocol":1,"default_usage":{"*any":"3h0m0s","*data":"1048576","*sms":"1","*voice":"3h0m0s"},"enabled":false,"listen_bigob":"","listen_bijson":"127.0.0.1:2014","min_dur_low_balance":"0","opts":{"*accounts":[{"FilterIDs":null,"Tenant":""}],"*accountsForceUsage":[],"*attributes":[{"FilterIDs":null,"Tenant":""}],"*attributesDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*blockerError":[{"FilterIDs":null,"Tenant":""}],"*cdrs":[{"FilterIDs":null,"Tenant":""}],"*cdrsDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*chargeable":[{"FilterIDs":null,"Tenant":""}],"*chargers":[{"FilterIDs":null,"Tenant":""}],"*debitInterval":[{"FilterIDs":null,"Tenant":""}],"*forceUsage":[],"*initiate":[{"FilterIDs":null,"Tenant":""}],"*maxUsage":[{"FilterIDs":null,"Tenant":""}],"*message":[{"FilterIDs":null,"Tenant":""}],"*originID":[],"*resources":[{"FilterIDs":null,"Tenant":""}],"*resourcesAllocate":[{"FilterIDs":null,"Tenant":""}],"*resourcesAuthorize":[{"FilterIDs":null,"Tenant":""}],"*resourcesDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*resourcesRelease":[{"FilterIDs":null,"Tenant":""}],"*routes":[{"FilterIDs":null,"Tenant":""}],"*routesDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*stats":[{"FilterIDs":null,"Tenant":""}],"*statsDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*terminate":[{"FilterIDs":null,"Tenant":""}],"*thresholds":[{"FilterIDs":null,"Tenant":""}],"*thresholdsDerivedReply":[{"FilterIDs":null,"Tenant":""}],"*ttl":[{"FilterIDs":null,"Tenant":""}],"*ttlLastUsage":[],"*ttlLastUsed":[],"*ttlMaxDelay":[{"FilterIDs":null,"Tenant":""}],"*ttlUsage":[],"*update":[{"FilterIDs":null,"Tenant":""}]},"rates_conns":[],"replication_conns":[],"resources_conns":[],"routes_conns":[],"session_indexes":[],"stats_conns":[],"stir":{"allowed_attest":["*any"],"default_attest":"A","payload_maxduration":"-1","privatekey_path":"","publickey_path":""},"store_session_costs":false,"terminate_attempts":5,"thresholds_conns":[]},"sip_agent":{"enabled":false,"listen":"127.0.0.1:5060","listen_net":"udp","request_processors":[],"retransmission_timer":"1s","sessions_conns":["*internal"],"timezone":""},"stats":{"ees_conns":[],"ees_exporter_ids":null,"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}],"*roundingDecimals":[]},"prefix_indexed_fields":[],"store_interval":"","store_uncompressed_limit":0,"suffix_indexed_fields":[],"thresholds_conns":[]},"stor_db":{"db_host":"127.0.0.1","db_name":"cgrates","db_password":"CGRateS.org","db_port":3306,"db_type":"**mysql","db_user":"cgrates","items":{"*cdrs":{"limit":-1,"remote":false,"replicate":false,"static_ttl":false}},"opts":{"internalDBBackupPath":"/var/lib/cgrates/internal_db/backup/stordb","internalDBDumpInterval":"0s","internalDBDumpPath":"/var/lib/cgrates/internal_db/stordb","internalDBFileSizeLimit":1073741824,"internalDBRewriteInterval":"0s","internalDBStartTimeout":"5m0s","mongoConnScheme":"mongodb","mongoQueryTimeout":"10s","mysqlDSNParams":{},"mysqlLocation":"Local","pgSSLMode":"disable","sqlConnMaxLifetime":"0s","sqlLogLevel":3,"sqlMaxIdleConns":10,"sqlMaxOpenConns":100},"prefix_indexed_fields":[],"remote_conns":null,"replication_conns":null,"string_indexed_fields":[]},"suretax":{"bill_to_number":"","business_unit":"","client_number":"","client_tracking":"~*opts.*originID","customer_number":"~*req.Subject","include_local_cost":false,"orig_number":"~*req.Subject","p2pplus4":"","p2pzipcode":"","plus4":"","regulatory_code":"03","response_group":"03","response_type":"D4","return_file_code":"0","sales_type_code":"R","tax_exemption_code_list":"","tax_included":"0","tax_situs_rule":"04","term_number":"~*req.Destination","timezone":"UTC","trans_type_code":"010101","unit_type":"00","units":"1","url":"","validation_key":"","zipcode":""},"templates":{"*asr":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"}],"*cca":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"path":"*rep.Result-Code","tag":"ResultCode","type":"*constant","value":"2001"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"},{"mandatory":true,"path":"*rep.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"mandatory":true,"path":"*rep.CC-Request-Type","tag":"CCRequestType","type":"*variable","value":"~*req.CC-Request-Type"},{"mandatory":true,"path":"*rep.CC-Request-Number","tag":"CCRequestNumber","type":"*variable","value":"~*req.CC-Request-Number"}],"*cdrLog":[{"mandatory":true,"path":"*cdr.ToR","tag":"ToR","type":"*variable","value":"~*req.BalanceType"},{"mandatory":true,"path":"*cdr.OriginHost","tag":"OriginHost","type":"*constant","value":"127.0.0.1"},{"mandatory":true,"path":"*cdr.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"mandatory":true,"path":"*cdr.Tenant","tag":"Tenant","type":"*variable","value":"~*req.Tenant"},{"mandatory":true,"path":"*cdr.Account","tag":"Account","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Subject","tag":"Subject","type":"*variable","value":"~*req.Account"},{"mandatory":true,"path":"*cdr.Cost","tag":"Cost","type":"*variable","value":"~*req.Cost"},{"mandatory":true,"path":"*cdr.Source","tag":"Source","type":"*constant","value":"*cdrLog"},{"mandatory":true,"path":"*cdr.Usage","tag":"Usage","type":"*constant","value":"1"},{"mandatory":true,"path":"*cdr.RunID","tag":"RunID","type":"*variable","value":"~*req.ActionType"},{"mandatory":true,"path":"*cdr.SetupTime","tag":"SetupTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.AnswerTime","tag":"AnswerTime","type":"*constant","value":"*now"},{"mandatory":true,"path":"*cdr.PreRated","tag":"PreRated","type":"*constant","value":"true"}],"*err":[{"mandatory":true,"path":"*rep.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*rep.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*vars.OriginHost"},{"mandatory":true,"path":"*rep.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*vars.OriginRealm"}],"*errSip":[{"mandatory":true,"path":"*rep.Request","tag":"Request","type":"*constant","value":"SIP/2.0 500 Internal Server Error"}],"*fsa":[{"path":"*cgreq.ToR","tag":"ToR","type":"*constant","value":"*voice"},{"path":"*cgreq.PDD","tag":"PDD","type":"*composed","value":"~*req.variable_progress_mediamsec;ms"},{"path":"*cgreq.ACD","tag":"ACD","type":"*composed","value":"~*req.variable_cdr_acd;s"},{"path":"*cgreq.OriginID","tag":"OriginID","type":"*variable","value":"~*req.Unique-ID"},{"path":"*opts.*originID","tag":"*originID","type":"*variable","value":"~*req.Unique-ID"},{"path":"*cgreq.OriginHost","tag":"OriginHost","type":"*variable","value":"~*req.variable_cgr_originhost"},{"path":"*cgreq.Account","tag":"Account","type":"*variable","value":"~*req.Caller-Username"},{"path":"*cgreq.Source","tag":"Source","type":"*composed","value":"FS_;~*req.Event-Name"},{"filters":["*string:*req.variable_process_cdr:false"],"path":"*cgreq.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"filters":["*string:*req.Caller-Dialplan:inline"],"path":"*cgreq.RequestType","tag":"RequestType","type":"*constant","value":"*none"},{"filters":["*exists:*cgreq.RequestType:"],"path":"*cgreq.RequestType","tag":"RequestType","type":"*constant","value":"*prepaid"},{"path":"*cgreq.Tenant","tag":"Tenant","type":"*constant","value":"cgrates.org"},{"path":"*cgreq.Category","tag":"Category","type":"*constant","value":"call"},{"path":"*cgreq.Subject","tag":"Subject","type":"*variable","value":"~*req.Caller-Username"},{"path":"*cgreq.Destination","tag":"Destination","type":"*variable","value":"~*req.Caller-Destination-Number"},{"path":"*cgreq.SetupTime","tag":"SetupTime","type":"*variable","value":"~*req.Caller-Channel-Created-Time"},{"path":"*cgreq.AnswerTime","tag":"AnswerTime","type":"*variable","value":"~*req.Caller-Channel-Answered-Time"},{"path":"*cgreq.Usage","tag":"Usage","type":"*composed","value":"~*req.variable_billsec;s"},{"path":"*cgreq.Route","tag":"Route","type":"*variable","value":"~*req.variable_cgr_route"},{"path":"*cgreq.Cost","tag":"Cost","type":"*constant","value":"-1.0"},{"filters":["*notempty:*req.Hangup-Cause:"],"path":"*cgreq.DisconnectCause","tag":"DisconnectCause","type":"*variable","value":"~*req.Hangup-Cause"}],"*rar":[{"mandatory":true,"path":"*diamreq.Session-Id","tag":"SessionId","type":"*variable","value":"~*req.Session-Id"},{"mandatory":true,"path":"*diamreq.Origin-Host","tag":"OriginHost","type":"*variable","value":"~*req.Destination-Host"},{"mandatory":true,"path":"*diamreq.Origin-Realm","tag":"OriginRealm","type":"*variable","value":"~*req.Destination-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Realm","tag":"DestinationRealm","type":"*variable","value":"~*req.Origin-Realm"},{"mandatory":true,"path":"*diamreq.Destination-Host","tag":"DestinationHost","type":"*variable","value":"~*req.Origin-Host"},{"mandatory":true,"path":"*diamreq.Auth-Application-Id","tag":"AuthApplicationId","type":"*variable","value":"~*vars.*appid"},{"path":"*diamreq.Re-Auth-Request-Type","tag":"ReAuthRequestType","type":"*constant","value":"0"}]},"thresholds":{"actions_conns":[],"enabled":false,"exists_indexed_fields":[],"indexed_selects":true,"nested_fields":false,"notexists_indexed_fields":[],"opts":{"*profileIDs":[],"*profileIgnoreFilters":[{"FilterIDs":null,"Tenant":""}]},"prefix_indexed_fields":[],"store_interval":"","suffix_indexed_fields":[]},"tls":{"ca_certificate":"","client_certificate":"","client_key":"","server_certificate":"","server_key":"","server_name":"","server_policy":4},"tpes":{"enabled":false},"trends":{"ees_conns":[],"ees_exporter_ids":null,"enabled":false,"scheduled_ids":{},"stats_conns":[],"store_interval":"","store_uncompressed_limit":0,"thresholds_conns":[]}}`
cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSON)
if err != nil {
diff --git a/config/configsanity.go b/config/configsanity.go
index 3b8c3dfd8..779094ae5 100644
--- a/config/configsanity.go
+++ b/config/configsanity.go
@@ -112,7 +112,7 @@ func (cfg *CGRConfig) checkConfigSanity() error {
}
}
for _, data := range ldrSCfg.Data {
- if !posibleLoaderTypes.Has(data.Type) {
+ if !possibleLoaderTypes.Has(data.Type) {
return fmt.Errorf("<%s> unsupported data type %s", utils.LoaderS, data.Type)
}
diff --git a/config/ips.go b/config/ips.go
new file mode 100644
index 000000000..c6ba42ebb
--- /dev/null
+++ b/config/ips.go
@@ -0,0 +1,268 @@
+/*
+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 config
+
+import (
+ "slices"
+ "time"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/utils"
+)
+
+const (
+ IPsUsageIDDftOpt = utils.EmptyString
+ IPsTTLDftOpt = 72 * time.Hour
+ IPsUnitsDftOpt = 1
+)
+
+// IPsJsonCfg holds the unparsed ips section configuration as found in the
+// config file.
+type IPsJsonCfg struct {
+ Enabled *bool `json:"enabled"`
+ IndexedSelects *bool `json:"indexed_selects"`
+ StoreInterval *string `json:"store_interval"`
+ StringIndexedFields *[]string `json:"string_indexed_fields"`
+ PrefixIndexedFields *[]string `json:"prefix_indexed_fields"`
+ SuffixIndexedFields *[]string `json:"suffix_indexed_fields"`
+ ExistsIndexedFields *[]string `json:"exists_indexed_fields"`
+ NotExistsIndexedFields *[]string `json:"not_exists_indexed_fields"`
+ NestedFields *bool `json:"nested_fields"`
+ Opts *IPsOptsJson `json:"opts"`
+}
+
+// IPsCfg represents the configuration of the IPs module.
+type IPsCfg struct {
+ Enabled bool
+ IndexedSelects bool
+ StoreInterval time.Duration
+ StringIndexedFields *[]string
+ PrefixIndexedFields *[]string
+ SuffixIndexedFields *[]string
+ ExistsIndexedFields *[]string
+ NotExistsIndexedFields *[]string
+ NestedFields bool
+ Opts *IPsOpts
+}
+
+// Load loads the IPs section of the configuration.
+func (rlcfg *IPsCfg) Load(ctx *context.Context, jsnCfg ConfigDB, _ *CGRConfig) (err error) {
+ jsnRLSCfg := new(IPsJsonCfg)
+ if err = jsnCfg.GetSection(ctx, IPsJSON, jsnRLSCfg); err != nil {
+ return
+ }
+ return rlcfg.loadFromJSONCfg(jsnRLSCfg)
+}
+
+func (IPsCfg) SName() string { return IPsJSON }
+func (c IPsCfg) CloneSection() Section { return c.Clone() }
+
+func (c *IPsCfg) loadFromJSONCfg(jc *IPsJsonCfg) error {
+ if jc == nil {
+ return nil
+ }
+ if jc.Enabled != nil {
+ c.Enabled = *jc.Enabled
+ }
+ if jc.IndexedSelects != nil {
+ c.IndexedSelects = *jc.IndexedSelects
+ }
+ if jc.StoreInterval != nil {
+ v, err := utils.ParseDurationWithNanosecs(*jc.StoreInterval)
+ if err != nil {
+ return err
+ }
+ c.StoreInterval = v
+ }
+ if jc.StringIndexedFields != nil {
+ sif := slices.Clone(*jc.StringIndexedFields)
+ c.StringIndexedFields = &sif
+ }
+ if jc.PrefixIndexedFields != nil {
+ pif := slices.Clone(*jc.PrefixIndexedFields)
+ c.PrefixIndexedFields = &pif
+ }
+ if jc.SuffixIndexedFields != nil {
+ sif := slices.Clone(*jc.SuffixIndexedFields)
+ c.SuffixIndexedFields = &sif
+ }
+ if jc.ExistsIndexedFields != nil {
+ eif := slices.Clone(*jc.ExistsIndexedFields)
+ c.ExistsIndexedFields = &eif
+ }
+ if jc.NotExistsIndexedFields != nil {
+ c.NotExistsIndexedFields = utils.SliceStringPointer(slices.Clone(*jc.NotExistsIndexedFields))
+ }
+ if jc.NestedFields != nil {
+ c.NestedFields = *jc.NestedFields
+ }
+ if jc.Opts != nil {
+ if err := c.Opts.loadFromJSONCfg(jc.Opts); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Clone returns a deep copy of IPsCfg.
+func (c IPsCfg) Clone() *IPsCfg {
+ clone := &IPsCfg{
+ Enabled: c.Enabled,
+ IndexedSelects: c.IndexedSelects,
+ StoreInterval: c.StoreInterval,
+ NestedFields: c.NestedFields,
+ Opts: c.Opts.Clone(),
+ }
+ if c.StringIndexedFields != nil {
+ idx := slices.Clone(*c.StringIndexedFields)
+ clone.StringIndexedFields = &idx
+ }
+ if c.PrefixIndexedFields != nil {
+ idx := slices.Clone(*c.PrefixIndexedFields)
+ clone.PrefixIndexedFields = &idx
+ }
+ if c.SuffixIndexedFields != nil {
+ idx := slices.Clone(*c.SuffixIndexedFields)
+ clone.SuffixIndexedFields = &idx
+ }
+ if c.ExistsIndexedFields != nil {
+ idx := slices.Clone(*c.ExistsIndexedFields)
+ clone.ExistsIndexedFields = &idx
+ }
+ if c.NotExistsIndexedFields != nil {
+ idx := slices.Clone(*c.NotExistsIndexedFields)
+ clone.NotExistsIndexedFields = &idx
+ }
+ return clone
+}
+
+// AsMapInterface returns the ips config as a map[string]any.
+func (c IPsCfg) AsMapInterface() any {
+ return map[string]any{
+ utils.EnabledCfg: c.Enabled,
+ utils.IndexedSelectsCfg: c.IndexedSelects,
+ utils.NestedFieldsCfg: c.NestedFields,
+ utils.StoreIntervalCfg: c.StoreInterval.String(),
+ utils.StringIndexedFieldsCfg: c.StringIndexedFields,
+ utils.PrefixIndexedFieldsCfg: c.PrefixIndexedFields,
+ utils.SuffixIndexedFieldsCfg: c.SuffixIndexedFields,
+ utils.ExistsIndexedFieldsCfg: c.ExistsIndexedFields,
+ utils.NotExistsIndexedFieldsCfg: c.NotExistsIndexedFields,
+ utils.OptsCfg: c.Opts.AsMapInterface(),
+ }
+}
+
+type IPsOptsJson struct {
+ UsageID []*DynamicInterfaceOpt `json:"*usageID"`
+ TTL []*DynamicInterfaceOpt `json:"*ttl"`
+ Units []*DynamicInterfaceOpt `json:"*units"`
+}
+
+type IPsOpts struct {
+ UsageID []*DynamicStringOpt
+ TTL []*DynamicDurationOpt
+ Units []*DynamicFloat64Opt
+}
+
+func (o *IPsOpts) loadFromJSONCfg(jc *IPsOptsJson) error {
+ if jc == nil {
+ return nil
+ }
+ if jc.UsageID != nil {
+ usageID, err := InterfaceToDynamicStringOpts(jc.UsageID)
+ if err != nil {
+ return err
+ }
+ o.UsageID = append(o.UsageID, usageID...)
+ }
+ if jc.TTL != nil {
+ ttl, err := IfaceToDurationDynamicOpts(jc.TTL)
+ if err != nil {
+ return err
+ }
+ o.TTL = append(o.TTL, ttl...)
+ }
+ if jc.Units != nil {
+ units, err := InterfaceToFloat64DynamicOpts(jc.Units)
+ if err != nil {
+ return err
+ }
+ o.Units = append(o.Units, units...)
+ }
+ return nil
+}
+
+// Clone returns a deep copy of IPsOpts.
+func (o *IPsOpts) Clone() *IPsOpts {
+ return &IPsOpts{
+ UsageID: CloneDynamicStringOpt(o.UsageID),
+ TTL: CloneDynamicDurationOpt(o.TTL),
+ Units: CloneDynamicFloat64Opt(o.Units),
+ }
+}
+
+// AsMapInterface returns the config as a map[string]any.
+func (o *IPsOpts) AsMapInterface() map[string]any {
+ return map[string]any{
+ utils.MetaUsageIDCfg: o.UsageID,
+ utils.MetaUnitsCfg: o.Units,
+ utils.MetaTTLCfg: o.TTL,
+ }
+}
+
+func diffIPsOptsJsonCfg(d *IPsOptsJson, v1, v2 *IPsOpts) *IPsOptsJson {
+ if d == nil {
+ d = new(IPsOptsJson)
+ }
+ if !DynamicStringOptEqual(v1.UsageID, v2.UsageID) {
+ d.UsageID = DynamicStringToInterfaceOpts(v2.UsageID)
+ }
+ if !DynamicDurationOptEqual(v1.TTL, v2.TTL) {
+ d.TTL = DurationToIfaceDynamicOpts(v2.TTL)
+ }
+ if !DynamicFloat64OptEqual(v1.Units, v2.Units) {
+ d.Units = Float64ToInterfaceDynamicOpts(v2.Units)
+ }
+ return d
+}
+
+func diffIPsJsonCfg(d *IPsJsonCfg, v1, v2 *IPsCfg) *IPsJsonCfg {
+ if d == nil {
+ d = new(IPsJsonCfg)
+ }
+ if v1.Enabled != v2.Enabled {
+ d.Enabled = utils.BoolPointer(v2.Enabled)
+ }
+ if v1.IndexedSelects != v2.IndexedSelects {
+ d.IndexedSelects = utils.BoolPointer(v2.IndexedSelects)
+ }
+ if v1.StoreInterval != v2.StoreInterval {
+ d.StoreInterval = utils.StringPointer(v2.StoreInterval.String())
+ }
+ d.StringIndexedFields = diffIndexSlice(d.StringIndexedFields, v1.StringIndexedFields, v2.StringIndexedFields)
+ d.PrefixIndexedFields = diffIndexSlice(d.PrefixIndexedFields, v1.PrefixIndexedFields, v2.PrefixIndexedFields)
+ d.SuffixIndexedFields = diffIndexSlice(d.SuffixIndexedFields, v1.SuffixIndexedFields, v2.SuffixIndexedFields)
+ d.ExistsIndexedFields = diffIndexSlice(d.ExistsIndexedFields, v1.ExistsIndexedFields, v2.ExistsIndexedFields)
+ d.NotExistsIndexedFields = diffIndexSlice(d.NotExistsIndexedFields, v1.NotExistsIndexedFields, v2.NotExistsIndexedFields)
+ if v1.NestedFields != v2.NestedFields {
+ d.NestedFields = utils.BoolPointer(v2.NestedFields)
+ }
+ d.Opts = diffIPsOptsJsonCfg(d.Opts, v1.Opts, v2.Opts)
+ return d
+}
diff --git a/config/loaderscfg_test.go b/config/loaderscfg_test.go
index 3e640cf82..83dfeff99 100644
--- a/config/loaderscfg_test.go
+++ b/config/loaderscfg_test.go
@@ -72,6 +72,7 @@ func TestLoaderSCfgloadFromJsonCfgCase1(t *testing.T) {
utils.MetaFilters: {Limit: -1, TTL: 5 * time.Second},
utils.MetaAttributes: {Limit: -1, TTL: 5 * time.Second},
utils.MetaResources: {Limit: -1, TTL: 5 * time.Second},
+ utils.MetaIPs: {Limit: -1, TTL: 5 * time.Second},
utils.MetaStats: {Limit: -1, TTL: 5 * time.Second},
utils.MetaThresholds: {Limit: -1, TTL: 5 * time.Second},
utils.MetaRoutes: {Limit: -1, TTL: 5 * time.Second},
@@ -190,6 +191,59 @@ func TestLoaderSCfgloadFromJsonCfgCase1(t *testing.T) {
Layout: time.RFC3339},
},
},
+ {
+ Type: utils.MetaIPs,
+ Filename: utils.IPsCsv,
+ Fields: []*FCTemplate{
+ {Tag: "Tenant",
+ Path: "Tenant",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.0", utils.InfieldSep),
+ Mandatory: true,
+ Layout: time.RFC3339},
+ {Tag: "ID",
+ Path: "ID",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.1", utils.InfieldSep),
+ Mandatory: true,
+ Layout: time.RFC3339},
+ {Tag: "FilterIDs",
+ Path: "FilterIDs",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.2", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Weights",
+ Path: "Weights",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.3", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "TTL",
+ Path: "TTL",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.4", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Type",
+ Path: "Type",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.5", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "AddressPool",
+ Path: "AddressPool",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.6", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Allocation",
+ Path: "Allocation",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.7", utils.InfieldSep),
+ Layout: time.RFC3339},
+ {Tag: "Stored",
+ Path: "Stored",
+ Type: utils.MetaVariable,
+ Value: utils.NewRSRParsersMustCompile("~*req.8", utils.InfieldSep),
+ Layout: time.RFC3339},
+ },
+ },
{
Type: utils.MetaStats,
Filename: utils.StatsCsv,
@@ -1235,6 +1289,69 @@ func TestLoaderCfgAsMapInterfaceCase1(t *testing.T) {
},
},
},
+ {
+ utils.TypeCfg: "*ips",
+ utils.FilenameCfg: "IPs.csv",
+ utils.FlagsCfg: flags,
+ utils.FieldsCfg: []map[string]any{
+ {
+ utils.TagCfg: "Tenant",
+ utils.PathCfg: "Tenant",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.0",
+ utils.MandatoryCfg: true,
+ },
+ {
+ utils.TagCfg: "ID",
+ utils.PathCfg: "ID",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.1",
+ utils.MandatoryCfg: true,
+ },
+ {
+ utils.TagCfg: "FilterIDs",
+ utils.PathCfg: "FilterIDs",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.2",
+ },
+ {
+ utils.TagCfg: "Weights",
+ utils.PathCfg: "Weights",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.3",
+ },
+ {
+ utils.TagCfg: "TTL",
+ utils.PathCfg: "TTL",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.4",
+ },
+ {
+ utils.TagCfg: "Type",
+ utils.PathCfg: "Type",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.5",
+ },
+ {
+ utils.TagCfg: "AddressPool",
+ utils.PathCfg: "AddressPool",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.6",
+ },
+ {
+ utils.TagCfg: "Allocation",
+ utils.PathCfg: "Allocation",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.7",
+ },
+ {
+ utils.TagCfg: "Stored",
+ utils.PathCfg: "Stored",
+ utils.TypeCfg: "*variable",
+ utils.ValueCfg: "~*req.8",
+ },
+ },
+ },
{
utils.TypeCfg: "*stats",
utils.FilenameCfg: "Stats.csv",
@@ -2027,6 +2144,7 @@ func TestLoaderCfgAsMapInterfaceCase1(t *testing.T) {
utils.MetaFilters: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaAttributes: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaResources: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
+ utils.MetaIPs: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaStats: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaThresholds: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
utils.MetaRoutes: map[string]any{utils.LimitCfg: -1, utils.TTLCfg: "5s", utils.PrecacheCfg: false, utils.RemoteCfg: false, utils.ReplicateCfg: false, utils.StaticTTLCfg: false},
diff --git a/data/tariffplans/loadRateTest/IPs.csv b/data/tariffplans/loadRateTest/IPs.csv
new file mode 100644
index 000000000..e69de29bb
diff --git a/data/tariffplans/testit/IPs.csv b/data/tariffplans/testit/IPs.csv
new file mode 100644
index 000000000..54e8535b8
--- /dev/null
+++ b/data/tariffplans/testit/IPs.csv
@@ -0,0 +1,2 @@
+#Tenant[0],Id[1],FilterIDs[2],Weights[3],TTL[4],Type[5],AddressPool[6],Allocation[7],Stored[8]
+cgrates.org,IPs1,*string:~*req.Account:1001,;10,1s,ipv4,172.16.1.1/24,alloc_success,true
diff --git a/data/tariffplans/testtp/IPs.csv b/data/tariffplans/testtp/IPs.csv
new file mode 100644
index 000000000..e69de29bb
diff --git a/engine/datadbmock.go b/engine/datadbmock.go
index 2be67b80b..9248befb7 100644
--- a/engine/datadbmock.go
+++ b/engine/datadbmock.go
@@ -49,6 +49,12 @@ type DataDBMock struct {
RemoveResourceDrvF func(ctx *context.Context, tnt, id string) error
SetResourceDrvF func(ctx *context.Context, r *utils.Resource) error
GetResourceDrvF func(ctx *context.Context, tenant, id string) (*utils.Resource, error)
+ GetIPProfileDrvF func(ctx *context.Context, tnt, id string) (*utils.IPProfile, error)
+ SetIPProfileDrvF func(ctx *context.Context, ipp *utils.IPProfile) error
+ RemoveIPProfileDrvF func(ctx *context.Context, tnt, id string) error
+ RemoveIPDrvF func(ctx *context.Context, tnt, id string) error
+ SetIPDrvF func(ctx *context.Context, ip *utils.IP) error
+ GetIPDrvF func(ctx *context.Context, tenant, id string) (*utils.IP, error)
SetTrendProfileDrvF func(ctx *context.Context, tr *utils.TrendProfile) (err error)
GetTrendProfileDrvF func(ctx *context.Context, tenant string, id string) (sq *utils.TrendProfile, err error)
RemTrendProfileDrvF func(ctx *context.Context, tenant string, id string) (err error)
@@ -163,6 +169,48 @@ func (dbM *DataDBMock) RemoveResourceDrv(ctx *context.Context, tnt, id string) e
return utils.ErrNotImplemented
}
+func (dbM *DataDBMock) GetIPProfileDrv(ctx *context.Context, tnt, id string) (*utils.IPProfile, error) {
+ if dbM.GetIPProfileDrvF != nil {
+ return dbM.GetIPProfileDrvF(ctx, tnt, id)
+ }
+ return nil, utils.ErrNotImplemented
+}
+
+func (dbM *DataDBMock) SetIPProfileDrv(ctx *context.Context, ipp *utils.IPProfile) error {
+ if dbM.SetIPProfileDrvF != nil {
+ return dbM.SetIPProfileDrvF(ctx, ipp)
+ }
+ return utils.ErrNotImplemented
+}
+
+func (dbM *DataDBMock) RemoveIPProfileDrv(ctx *context.Context, tnt string, id string) error {
+ if dbM.RemoveIPProfileDrvF != nil {
+ return dbM.RemoveIPProfileDrvF(ctx, tnt, id)
+ }
+ return utils.ErrNotImplemented
+}
+
+func (dbM *DataDBMock) GetIPDrv(ctx *context.Context, tenant, id string) (*utils.IP, error) {
+ if dbM.GetIPDrvF != nil {
+ return dbM.GetIPDrvF(ctx, tenant, id)
+ }
+ return nil, utils.ErrNotImplemented
+}
+
+func (dbM *DataDBMock) SetIPDrv(ctx *context.Context, ip *utils.IP) error {
+ if dbM.SetIPDrvF != nil {
+ return dbM.SetIPDrvF(ctx, ip)
+ }
+ return utils.ErrNotImplemented
+}
+
+func (dbM *DataDBMock) RemoveIPDrv(ctx *context.Context, tnt, id string) error {
+ if dbM.RemoveIPDrvF != nil {
+ return dbM.RemoveIPDrvF(ctx, tnt, id)
+ }
+ return utils.ErrNotImplemented
+}
+
func (dbM *DataDBMock) GetLoadHistory(int, bool, string) ([]*utils.LoadInstance, error) {
return nil, utils.ErrNotImplemented
}
diff --git a/engine/datamanager.go b/engine/datamanager.go
index 745b6277d..fe2bc1d94 100644
--- a/engine/datamanager.go
+++ b/engine/datamanager.go
@@ -34,6 +34,7 @@ var (
filterIndexesPrefixMap = utils.StringSet{
utils.AttributeFilterIndexes: {},
utils.ResourceFilterIndexes: {},
+ utils.IPFilterIndexes: {},
utils.StatFilterIndexes: {},
utils.ThresholdFilterIndexes: {},
utils.RouteFilterIndexes: {},
@@ -48,6 +49,8 @@ var (
cachePrefixMap = utils.StringSet{
utils.ResourceProfilesPrefix: {},
utils.ResourcesPrefix: {},
+ utils.IPProfilesPrefix: {},
+ utils.IPsPrefix: {},
utils.StatQueuePrefix: {},
utils.StatQueueProfilePrefix: {},
utils.ThresholdPrefix: {},
@@ -66,6 +69,7 @@ var (
utils.ActionProfilePrefix: {},
utils.AttributeFilterIndexes: {},
utils.ResourceFilterIndexes: {},
+ utils.IPFilterIndexes: {},
utils.StatFilterIndexes: {},
utils.ThresholdFilterIndexes: {},
utils.RouteFilterIndexes: {},
@@ -158,6 +162,16 @@ func (dm *DataManager) CacheDataFromDB(ctx *context.Context, prfx string, ids []
lkID := guardian.Guardian.GuardIDs("", dm.cfg.GeneralCfg().LockingTimeout, utils.ResourceLockKey(tntID.Tenant, tntID.ID))
_, err = dm.GetResource(ctx, tntID.Tenant, tntID.ID, false, true, utils.NonTransactional)
guardian.Guardian.UnguardIDs(lkID)
+ case utils.IPProfilesPrefix:
+ tntID := utils.NewTenantID(dataID)
+ lkID := guardian.Guardian.GuardIDs("", dm.cfg.GeneralCfg().LockingTimeout, utils.IPProfileLockKey(tntID.Tenant, tntID.ID))
+ _, err = dm.GetIPProfile(ctx, tntID.Tenant, tntID.ID, false, true, utils.NonTransactional)
+ guardian.Guardian.UnguardIDs(lkID)
+ case utils.IPsPrefix:
+ tntID := utils.NewTenantID(dataID)
+ lkID := guardian.Guardian.GuardIDs("", dm.cfg.GeneralCfg().LockingTimeout, utils.IPLockKey(tntID.Tenant, tntID.ID))
+ _, err = dm.GetIP(ctx, tntID.Tenant, tntID.ID, false, true, utils.NonTransactional)
+ guardian.Guardian.UnguardIDs(lkID)
case utils.StatQueueProfilePrefix:
tntID := utils.NewTenantID(dataID)
lkID := guardian.Guardian.GuardIDs("", dm.cfg.GeneralCfg().LockingTimeout, statQueueProfileLockKey(tntID.Tenant, tntID.ID))
@@ -216,6 +230,12 @@ func (dm *DataManager) CacheDataFromDB(ctx *context.Context, prfx string, ids []
return
}
_, err = dm.GetIndexes(ctx, utils.CacheResourceFilterIndexes, tntCtx, idxKey, utils.NonTransactional, false, true)
+ case utils.IPFilterIndexes:
+ var tntCtx, idxKey string
+ if tntCtx, idxKey, err = splitFilterIndex(dataID); err != nil {
+ return
+ }
+ _, err = dm.GetIndexes(ctx, utils.CacheIPFilterIndexes, tntCtx, idxKey, utils.NonTransactional, false, true)
case utils.StatFilterIndexes:
var tntCtx, idxKey string
if tntCtx, idxKey, err = splitFilterIndex(dataID); err != nil {
@@ -1663,6 +1683,241 @@ func (dm *DataManager) RemoveResourceProfile(ctx *context.Context, tenant, id st
return dm.RemoveResource(ctx, tenant, id)
}
+func (dm *DataManager) GetIP(ctx *context.Context, tenant, id string, cacheRead, cacheWrite bool,
+ transactionID string) (ip *utils.IP, err error) {
+ tntID := utils.ConcatenatedKey(tenant, id)
+ if cacheRead {
+ if x, ok := Cache.Get(utils.CacheIPs, tntID); ok {
+ if x == nil {
+ return nil, utils.ErrNotFound
+ }
+ return x.(*utils.IP), nil
+ }
+ }
+ if dm == nil {
+ err = utils.ErrNoDatabaseConn
+ return
+ }
+ ip, err = dm.dataDB.GetIPDrv(ctx, tenant, id)
+ if err != nil {
+ if itm := dm.cfg.DataDbCfg().Items[utils.MetaIPs]; err == utils.ErrNotFound && itm.Remote {
+ if err = dm.connMgr.Call(ctx, dm.cfg.DataDbCfg().RmtConns,
+ utils.ReplicatorSv1GetIP,
+ &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{Tenant: tenant, ID: id},
+ APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, utils.EmptyString,
+ utils.FirstNonEmpty(dm.cfg.DataDbCfg().RmtConnID,
+ dm.cfg.GeneralCfg().NodeID)),
+ }, &ip); err == nil {
+ err = dm.dataDB.SetIPDrv(ctx, ip)
+ }
+ }
+ if err != nil {
+ err = utils.CastRPCErr(err)
+ if err == utils.ErrNotFound && cacheWrite {
+ if errCh := Cache.Set(ctx, utils.CacheIPs, tntID, nil, nil,
+ cacheCommit(transactionID), transactionID); errCh != nil {
+ return nil, errCh
+ }
+
+ }
+ return nil, err
+ }
+ }
+ if cacheWrite {
+ if errCh := Cache.Set(ctx, utils.CacheIPs, tntID, ip, nil,
+ cacheCommit(transactionID), transactionID); errCh != nil {
+ return nil, errCh
+ }
+ }
+ return
+}
+
+func (dm *DataManager) SetIP(ctx *context.Context, ip *utils.IP) (err error) {
+ if dm == nil {
+ return utils.ErrNoDatabaseConn
+ }
+ if err = dm.DataDB().SetIPDrv(ctx, ip); err != nil {
+ return
+ }
+ if itm := dm.cfg.DataDbCfg().Items[utils.MetaIPs]; itm.Replicate {
+ err = replicate(ctx, dm.connMgr, dm.cfg.DataDbCfg().RplConns,
+ dm.cfg.DataDbCfg().RplFiltered,
+ utils.IPsPrefix, ip.TenantID(), // this are used to get the host IDs from cache
+ utils.ReplicatorSv1SetIP,
+ &utils.IPWithAPIOpts{
+ IP: ip,
+ APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID,
+ dm.cfg.DataDbCfg().RplCache, utils.EmptyString)})
+ }
+ return
+}
+
+func (dm *DataManager) RemoveIP(ctx *context.Context, tenant, id string) (err error) {
+ if dm == nil {
+ return utils.ErrNoDatabaseConn
+ }
+ if err = dm.DataDB().RemoveIPDrv(ctx, tenant, id); err != nil {
+ return
+ }
+ if itm := dm.cfg.DataDbCfg().Items[utils.MetaIPs]; itm.Replicate {
+ replicate(ctx, dm.connMgr, dm.cfg.DataDbCfg().RplConns,
+ dm.cfg.DataDbCfg().RplFiltered,
+ utils.IPsPrefix, utils.ConcatenatedKey(tenant, id), // this are used to get the host IDs from cache
+ utils.ReplicatorSv1RemoveIP,
+ &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{Tenant: tenant, ID: id},
+ APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID,
+ dm.cfg.DataDbCfg().RplCache, utils.EmptyString)})
+ }
+ return
+}
+
+func (dm *DataManager) GetIPProfile(ctx *context.Context, tenant, id string, cacheRead, cacheWrite bool,
+ transactionID string) (ipp *utils.IPProfile, err error) {
+ tntID := utils.ConcatenatedKey(tenant, id)
+ if cacheRead {
+ if x, ok := Cache.Get(utils.CacheIPProfiles, tntID); ok {
+ if x == nil {
+ return nil, utils.ErrNotFound
+ }
+ return x.(*utils.IPProfile), nil
+ }
+ }
+ if dm == nil {
+ err = utils.ErrNoDatabaseConn
+ return
+ }
+ ipp, err = dm.dataDB.GetIPProfileDrv(ctx, tenant, id)
+ if err != nil {
+ if itm := dm.cfg.DataDbCfg().Items[utils.MetaIPProfiles]; err == utils.ErrNotFound && itm.Remote {
+ if err = dm.connMgr.Call(ctx, dm.cfg.DataDbCfg().RmtConns,
+ utils.ReplicatorSv1GetIPProfile, &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{Tenant: tenant, ID: id},
+ APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID, utils.EmptyString,
+ utils.FirstNonEmpty(dm.cfg.DataDbCfg().RmtConnID,
+ dm.cfg.GeneralCfg().NodeID)),
+ }, &ipp); err == nil {
+ err = dm.dataDB.SetIPProfileDrv(ctx, ipp)
+ }
+ }
+ if err != nil {
+ err = utils.CastRPCErr(err)
+ if err == utils.ErrNotFound && cacheWrite {
+ if errCh := Cache.Set(ctx, utils.CacheIPProfiles, tntID, nil, nil,
+ cacheCommit(transactionID), transactionID); errCh != nil {
+ return nil, errCh
+ }
+
+ }
+ return nil, err
+ }
+ }
+ if cacheWrite {
+ if errCh := Cache.Set(ctx, utils.CacheIPProfiles, tntID, ipp, nil,
+ cacheCommit(transactionID), transactionID); errCh != nil {
+ return nil, errCh
+ }
+ }
+ return
+}
+
+func (dm *DataManager) SetIPProfile(ctx *context.Context, ipp *utils.IPProfile, withIndex bool) (err error) {
+ if dm == nil {
+ return utils.ErrNoDatabaseConn
+ }
+ if withIndex {
+ if err := dm.checkFilters(ctx, ipp.Tenant, ipp.FilterIDs); err != nil {
+ // if we get a broken filter do not set the profile
+ return fmt.Errorf("%+s for item with ID: %+v",
+ err, ipp.TenantID())
+ }
+ }
+ oldIPP, err := dm.GetIPProfile(ctx, ipp.Tenant, ipp.ID, true, false, utils.NonTransactional)
+ if err != nil && err != utils.ErrNotFound {
+ return err
+ }
+ if err = dm.DataDB().SetIPProfileDrv(ctx, ipp); err != nil {
+ return err
+ }
+ if withIndex {
+ var oldFiltersIDs *[]string
+ if oldIPP != nil {
+ oldFiltersIDs = &oldIPP.FilterIDs
+ }
+ if err := updatedIndexes(ctx, dm, utils.CacheIPFilterIndexes, ipp.Tenant,
+ utils.EmptyString, ipp.ID, oldFiltersIDs, ipp.FilterIDs, false); err != nil {
+ return err
+ }
+ Cache.Clear([]string{utils.CacheEventIPs})
+ }
+ if itm := dm.cfg.DataDbCfg().Items[utils.MetaIPProfiles]; itm.Replicate {
+ if err = replicate(ctx, dm.connMgr, dm.cfg.DataDbCfg().RplConns,
+ dm.cfg.DataDbCfg().RplFiltered,
+ utils.IPProfilesPrefix, ipp.TenantID(), // this are used to get the host IDs from cache
+ utils.ReplicatorSv1SetIPProfile,
+ &utils.IPProfileWithAPIOpts{
+ IPProfile: ipp,
+ APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID,
+ dm.cfg.DataDbCfg().RplCache, utils.EmptyString)}); err != nil {
+ return
+ }
+ }
+ if oldIPP == nil || // create the resource if it didn't exist before
+ oldIPP.TTL != ipp.TTL ||
+ oldIPP.Stored != ipp.Stored && oldIPP.Stored { // reset the resource if the profile changed this fields
+ err = dm.SetIP(ctx, &utils.IP{
+ Tenant: ipp.Tenant,
+ ID: ipp.ID,
+ Usages: make(map[string]*utils.IPUsage),
+ })
+ } else if _, errRs := dm.GetIP(ctx, ipp.Tenant, ipp.ID, // do not try to get the resource if the configuration changed
+ true, false, utils.NonTransactional); errRs == utils.ErrNotFound { // the resource does not exist
+ err = dm.SetIP(ctx, &utils.IP{
+ Tenant: ipp.Tenant,
+ ID: ipp.ID,
+ Usages: make(map[string]*utils.IPUsage),
+ })
+ }
+ return
+}
+
+func (dm *DataManager) RemoveIPProfile(ctx *context.Context, tenant, id string, withIndex bool) (err error) {
+ if dm == nil {
+ return utils.ErrNoDatabaseConn
+ }
+ oldIPP, err := dm.GetIPProfile(ctx, tenant, id, true, false, utils.NonTransactional)
+ if err != nil && err != utils.ErrNotFound {
+ return err
+ }
+ if err = dm.DataDB().RemoveIPProfileDrv(ctx, tenant, id); err != nil {
+ return
+ }
+ if oldIPP == nil {
+ return utils.ErrNotFound
+ }
+ if withIndex {
+ if err = removeIndexFiltersItem(ctx, dm, utils.CacheIPFilterIndexes, tenant, id, oldIPP.FilterIDs); err != nil {
+ return
+ }
+ if err = removeItemFromFilterIndex(ctx, dm, utils.CacheIPFilterIndexes,
+ tenant, utils.EmptyString, id, oldIPP.FilterIDs); err != nil {
+ return
+ }
+ }
+ if itm := dm.cfg.DataDbCfg().Items[utils.MetaIPProfiles]; itm.Replicate {
+ replicate(ctx, dm.connMgr, dm.cfg.DataDbCfg().RplConns,
+ dm.cfg.DataDbCfg().RplFiltered,
+ utils.IPProfilesPrefix, utils.ConcatenatedKey(tenant, id), // this are used to get the host IDs from cache
+ utils.ReplicatorSv1RemoveIPProfile,
+ &utils.TenantIDWithAPIOpts{
+ TenantID: &utils.TenantID{Tenant: tenant, ID: id},
+ APIOpts: utils.GenerateDBItemOpts(itm.APIKey, itm.RouteID,
+ dm.cfg.DataDbCfg().RplCache, utils.EmptyString)})
+ }
+ return dm.RemoveIP(ctx, tenant, id)
+}
+
func (dm *DataManager) HasData(category, subject, tenant string) (has bool, err error) {
if dm == nil {
err = utils.ErrNoDatabaseConn
diff --git a/engine/libengine.go b/engine/libengine.go
index 621c51f2f..0f63f47e9 100644
--- a/engine/libengine.go
+++ b/engine/libengine.go
@@ -234,6 +234,9 @@ func NewDispatcherService(val any) (_ IntService, err error) {
case strings.HasPrefix(m, utils.ResourceS):
m = strings.TrimPrefix(m, utils.ResourceS)
key = utils.ResourceS
+ case strings.HasPrefix(m, utils.IPs):
+ m = strings.TrimPrefix(m, utils.IPs)
+ key = utils.IPs
case strings.HasPrefix(m, utils.RouteS):
m = strings.TrimPrefix(m, utils.RouteS)
key = utils.RouteS
diff --git a/engine/libtest.go b/engine/libtest.go
index dff7d7acc..1045c759e 100644
--- a/engine/libtest.go
+++ b/engine/libtest.go
@@ -273,10 +273,14 @@ func GetDefaultEmptyCacheStats() map[string]*ltcache.CacheStats {
utils.CacheChargerFilterIndexes: {},
utils.CacheChargerProfiles: {},
utils.CacheEventResources: {},
+ utils.CacheEventIPs: {},
utils.CacheFilters: {},
utils.CacheResourceFilterIndexes: {},
utils.CacheResourceProfiles: {},
utils.CacheResources: {},
+ utils.CacheIPFilterIndexes: {},
+ utils.CacheIPProfiles: {},
+ utils.CacheIPs: {},
utils.CacheRPCResponses: {},
utils.CacheStatFilterIndexes: {},
utils.CacheStatQueueProfiles: {},
@@ -585,6 +589,7 @@ var serviceReceivers = map[string]string{
utils.ERs: utils.ErSv1,
utils.RateS: utils.RateSv1,
utils.ResourceS: utils.ResourceSv1,
+ utils.IPs: utils.IPsV1,
utils.RouteS: utils.RouteSv1,
utils.SessionS: utils.SessionSv1,
utils.StatS: utils.StatSv1,
diff --git a/engine/storage_interface.go b/engine/storage_interface.go
index 3f297d0fe..6d84af22b 100644
--- a/engine/storage_interface.go
+++ b/engine/storage_interface.go
@@ -46,6 +46,12 @@ type DataDB interface {
GetResourceDrv(*context.Context, string, string) (*utils.Resource, error)
SetResourceDrv(*context.Context, *utils.Resource) error
RemoveResourceDrv(*context.Context, string, string) error
+ GetIPProfileDrv(*context.Context, string, string) (*utils.IPProfile, error)
+ SetIPProfileDrv(*context.Context, *utils.IPProfile) error
+ RemoveIPProfileDrv(*context.Context, string, string) error
+ GetIPDrv(*context.Context, string, string) (*utils.IP, error)
+ SetIPDrv(*context.Context, *utils.IP) error
+ RemoveIPDrv(*context.Context, string, string) error
GetLoadHistory(int, bool, string) ([]*utils.LoadInstance, error)
AddLoadHistory(*utils.LoadInstance, int, string) error
GetIndexesDrv(ctx *context.Context, idxItmType, tntCtx, idxKey, transactionID string) (indexes map[string]utils.StringSet, err error)
diff --git a/engine/storage_internal_datadb.go b/engine/storage_internal_datadb.go
index 834633049..a36b70d43 100644
--- a/engine/storage_internal_datadb.go
+++ b/engine/storage_internal_datadb.go
@@ -241,6 +241,44 @@ func (iDB *InternalDB) RemoveResourceDrv(_ *context.Context, tenant, id string)
return
}
+func (iDB *InternalDB) GetIPProfileDrv(_ *context.Context, tenant, id string) (*utils.IPProfile, error) {
+ if x, ok := iDB.db.Get(utils.CacheIPProfiles, utils.ConcatenatedKey(tenant, id)); ok && x != nil {
+ return x.(*utils.IPProfile), nil
+ }
+ return nil, utils.ErrNotFound
+}
+
+func (iDB *InternalDB) SetIPProfileDrv(_ *context.Context, ipp *utils.IPProfile) error {
+ iDB.db.Set(utils.CacheIPProfiles, ipp.TenantID(), ipp, nil,
+ true, utils.NonTransactional)
+ return nil
+}
+
+func (iDB *InternalDB) RemoveIPProfileDrv(_ *context.Context, tenant, id string) error {
+ iDB.db.Remove(utils.CacheIPProfiles, utils.ConcatenatedKey(tenant, id),
+ true, utils.NonTransactional)
+ return nil
+}
+
+func (iDB *InternalDB) GetIPDrv(_ *context.Context, tenant, id string) (*utils.IP, error) {
+ if x, ok := iDB.db.Get(utils.CacheIPs, utils.ConcatenatedKey(tenant, id)); ok && x != nil {
+ return x.(*utils.IP), nil
+ }
+ return nil, utils.ErrNotFound
+}
+
+func (iDB *InternalDB) SetIPDrv(_ *context.Context, ip *utils.IP) error {
+ iDB.db.Set(utils.CacheIPs, ip.TenantID(), ip, nil,
+ true, utils.NonTransactional)
+ return nil
+}
+
+func (iDB *InternalDB) RemoveIPDrv(_ *context.Context, tenant, id string) error {
+ iDB.db.Remove(utils.CacheIPs, utils.ConcatenatedKey(tenant, id),
+ true, utils.NonTransactional)
+ return nil
+}
+
func (iDB *InternalDB) GetLoadHistory(int, bool, string) ([]*utils.LoadInstance, error) {
return nil, nil
}
diff --git a/engine/storage_mongo_datadb.go b/engine/storage_mongo_datadb.go
index a038c3dc9..88f38f48e 100644
--- a/engine/storage_mongo_datadb.go
+++ b/engine/storage_mongo_datadb.go
@@ -57,8 +57,10 @@ const (
ColLht = "load_history"
ColVer = "versions"
ColRsP = "resource_profiles"
+ ColIPp = "ip_profiles"
ColIndx = "indexes"
ColRes = "resources"
+ ColIPs = "ips"
ColSqs = "statqueues"
ColSqp = "statqueue_profiles"
ColTps = "threshold_profiles"
@@ -299,7 +301,7 @@ func (ms *MongoStorage) ensureIndexesForCol(col string) error { // exported for
switch col {
case ColAct, ColApl, ColAAp, ColAtr, ColRpl, ColDst, ColRds, ColLht, ColIndx:
err = ms.ensureIndex(col, true, "key")
- case ColRsP, ColRes, ColSqs, ColRgp, ColTrs, ColTrd, ColSqp, ColTps, ColThs, ColRts, ColAttr, ColFlt, ColCpp, ColRpp, ColApp, ColAnp:
+ case ColRsP, ColRes, ColIPp, ColIPs, ColSqs, ColRgp, ColTrs, ColTrd, ColSqp, ColTps, ColThs, ColRts, ColAttr, ColFlt, ColCpp, ColRpp, ColApp, ColAnp:
err = ms.ensureIndex(col, true, "tenant", "id")
case ColRpf, ColShg, ColAcc:
err = ms.ensureIndex(col, true, "id")
@@ -323,8 +325,9 @@ func (ms *MongoStorage) EnsureIndexes(cols ...string) error {
if ms.IsDataDB() {
cols = []string{
ColAct, ColApl, ColAAp, ColAtr, ColRpl, ColDst, ColRds, ColLht, ColIndx,
- ColRsP, ColRes, ColSqs, ColSqp, ColTps, ColThs, ColRts, ColAttr, ColFlt,
- ColCpp, ColRpp, ColApp, ColRpf, ColShg, ColAcc, ColAnp, ColTrd, ColTrs,
+ ColRsP, ColRes, ColIPp, ColIPs, ColSqs, ColSqp, ColTps, ColThs, ColRts,
+ ColAttr, ColFlt, ColCpp, ColRpp, ColApp, ColRpf, ColShg, ColAcc, ColAnp,
+ ColTrd, ColTrs,
}
} else {
cols = []string{utils.CDRsTBL}
@@ -460,6 +463,10 @@ func (ms *MongoStorage) GetKeysForPrefix(ctx *context.Context, prefix string) (k
keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColRsP, utils.ResourceProfilesPrefix, tntID)
case utils.ResourcesPrefix:
keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColRes, utils.ResourcesPrefix, tntID)
+ case utils.IPProfilesPrefix:
+ keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColIPp, utils.IPProfilesPrefix, tntID)
+ case utils.IPsPrefix:
+ keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColIPs, utils.IPsPrefix, tntID)
case utils.StatQueuePrefix:
keys, qryErr = ms.getAllKeysMatchingTenantID(sctx, ColSqs, utils.StatQueuePrefix, tntID)
case utils.StatQueueProfilePrefix:
@@ -494,6 +501,8 @@ func (ms *MongoStorage) GetKeysForPrefix(ctx *context.Context, prefix string) (k
keys, qryErr = ms.getAllIndexKeys(sctx, utils.AttributeFilterIndexes)
case utils.ResourceFilterIndexes:
keys, qryErr = ms.getAllIndexKeys(sctx, utils.ResourceFilterIndexes)
+ case utils.IPFilterIndexes:
+ keys, qryErr = ms.getAllIndexKeys(sctx, utils.IPFilterIndexes)
case utils.StatFilterIndexes:
keys, qryErr = ms.getAllIndexKeys(sctx, utils.StatFilterIndexes)
case utils.ThresholdFilterIndexes:
@@ -530,6 +539,10 @@ func (ms *MongoStorage) HasDataDrv(ctx *context.Context, category, subject, tena
count, err = ms.getCol(ColRes).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject})
case utils.ResourceProfilesPrefix:
count, err = ms.getCol(ColRsP).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject})
+ case utils.IPsPrefix:
+ count, err = ms.getCol(ColIPs).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject})
+ case utils.IPProfilesPrefix:
+ count, err = ms.getCol(ColIPp).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject})
case utils.StatQueuePrefix:
count, err = ms.getCol(ColSqs).CountDocuments(sctx, bson.M{"tenant": tenant, "id": subject})
case utils.StatQueueProfilePrefix:
@@ -739,6 +752,72 @@ func (ms *MongoStorage) RemoveResourceDrv(ctx *context.Context, tenant, id strin
})
}
+func (ms *MongoStorage) GetIPProfileDrv(ctx *context.Context, tenant, id string) (*utils.IPProfile, error) {
+ ipp := new(utils.IPProfile)
+ err := ms.query(ctx, func(sctx mongo.SessionContext) error {
+ sr := ms.getCol(ColIPp).FindOne(sctx, bson.M{"tenant": tenant, "id": id})
+ decodeErr := sr.Decode(ipp)
+ if errors.Is(decodeErr, mongo.ErrNoDocuments) {
+ return utils.ErrNotFound
+ }
+ return decodeErr
+ })
+ return ipp, err
+}
+
+func (ms *MongoStorage) SetIPProfileDrv(ctx *context.Context, ipp *utils.IPProfile) error {
+ return ms.query(ctx, func(sctx mongo.SessionContext) error {
+ _, err := ms.getCol(ColIPp).UpdateOne(sctx, bson.M{"tenant": ipp.Tenant, "id": ipp.ID},
+ bson.M{"$set": ipp},
+ options.Update().SetUpsert(true),
+ )
+ return err
+ })
+}
+
+func (ms *MongoStorage) RemoveIPProfileDrv(ctx *context.Context, tenant, id string) error {
+ return ms.query(ctx, func(sctx mongo.SessionContext) error {
+ dr, err := ms.getCol(ColIPp).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id})
+ if dr.DeletedCount == 0 {
+ return utils.ErrNotFound
+ }
+ return err
+ })
+}
+
+func (ms *MongoStorage) GetIPDrv(ctx *context.Context, tenant, id string) (*utils.IP, error) {
+ ip := new(utils.IP)
+ err := ms.query(ctx, func(sctx mongo.SessionContext) error {
+ sr := ms.getCol(ColIPs).FindOne(sctx, bson.M{"tenant": tenant, "id": id})
+ decodeErr := sr.Decode(ip)
+ if errors.Is(decodeErr, mongo.ErrNoDocuments) {
+ return utils.ErrNotFound
+ }
+ return decodeErr
+ })
+ return ip, err
+}
+
+func (ms *MongoStorage) SetIPDrv(ctx *context.Context, ip *utils.IP) error {
+ return ms.query(ctx, func(sctx mongo.SessionContext) error {
+ _, err := ms.getCol(ColIPs).UpdateOne(sctx, bson.M{"tenant": ip.Tenant, "id": ip.ID},
+ bson.M{"$set": ip},
+ options.Update().SetUpsert(true),
+ )
+ return err
+ })
+}
+
+func (ms *MongoStorage) RemoveIPDrv(ctx *context.Context, tenant, id string) error {
+ return ms.query(ctx, func(sctx mongo.SessionContext) error {
+ dr, err := ms.getCol(ColIPs).DeleteOne(sctx, bson.M{"tenant": tenant, "id": id})
+ if dr.DeletedCount == 0 {
+ return utils.ErrNotFound
+ }
+ return err
+ })
+}
+
func (ms *MongoStorage) GetRankingProfileDrv(ctx *context.Context, tenant, id string) (*utils.RankingProfile, error) {
rgProfile := new(utils.RankingProfile)
err := ms.query(ctx, func(sctx mongo.SessionContext) error {
diff --git a/engine/storage_redis.go b/engine/storage_redis.go
index 4a9e8074b..5dcf0366f 100644
--- a/engine/storage_redis.go
+++ b/engine/storage_redis.go
@@ -420,6 +420,60 @@ func (rs *RedisStorage) RemoveResourceDrv(ctx *context.Context, tenant, id strin
return rs.Cmd(nil, redisDEL, utils.ResourcesPrefix+utils.ConcatenatedKey(tenant, id))
}
+func (rs *RedisStorage) GetIPProfileDrv(ctx *context.Context, tenant, id string) (*utils.IPProfile, error) {
+ var values []byte
+ if err := rs.Cmd(&values, redisGET, utils.IPProfilesPrefix+utils.ConcatenatedKey(tenant, id)); err != nil {
+ return nil, err
+ }
+ if len(values) == 0 {
+ return nil, utils.ErrNotFound
+ }
+ var ipp *utils.IPProfile
+ if err := rs.ms.Unmarshal(values, &ipp); err != nil {
+ return nil, err
+ }
+ return ipp, nil
+}
+
+func (rs *RedisStorage) SetIPProfileDrv(ctx *context.Context, ipp *utils.IPProfile) error {
+ result, err := rs.ms.Marshal(ipp)
+ if err != nil {
+ return err
+ }
+ return rs.Cmd(nil, redisSET, utils.IPProfilesPrefix+ipp.TenantID(), string(result))
+}
+
+func (rs *RedisStorage) RemoveIPProfileDrv(ctx *context.Context, tenant, id string) error {
+ return rs.Cmd(nil, redisDEL, utils.IPProfilesPrefix+utils.ConcatenatedKey(tenant, id))
+}
+
+func (rs *RedisStorage) GetIPDrv(ctx *context.Context, tenant, id string) (*utils.IP, error) {
+ var values []byte
+ if err := rs.Cmd(&values, redisGET, utils.IPsPrefix+utils.ConcatenatedKey(tenant, id)); err != nil {
+ return nil, err
+ }
+ if len(values) == 0 {
+ return nil, utils.ErrNotFound
+ }
+ var ip *utils.IP
+ if err := rs.ms.Unmarshal(values, &ip); err != nil {
+ return nil, err
+ }
+ return ip, nil
+}
+
+func (rs *RedisStorage) SetIPDrv(ctx *context.Context, ip *utils.IP) error {
+ result, err := rs.ms.Marshal(ip)
+ if err != nil {
+ return err
+ }
+ return rs.Cmd(nil, redisSET, utils.IPsPrefix+ip.TenantID(), string(result))
+}
+
+func (rs *RedisStorage) RemoveIPDrv(ctx *context.Context, tenant, id string) error {
+ return rs.Cmd(nil, redisDEL, utils.IPsPrefix+utils.ConcatenatedKey(tenant, id))
+}
+
func (rs *RedisStorage) GetVersions(itm string) (vrs Versions, err error) {
if itm != "" {
var fldVal int64
diff --git a/flaky_test.sh b/flaky_test.sh
index 05131a39a..0a4a49c63 100755
--- a/flaky_test.sh
+++ b/flaky_test.sh
@@ -8,7 +8,7 @@
# Example:
# ./flaky_tests.sh -dbtype=*mysql -rpc=*gob
-packages=("agents" "apis" "attributes" "chargers" "cmd/cgr-console" "cmd/cgr-loader" "efs" "engine" "ers" "general_tests" "loaders" "rankings" "registrarc" "resources" "routes" "sessions" "trends")
+packages=("agents" "apis" "attributes" "chargers" "cmd/cgr-console" "cmd/cgr-loader" "efs" "engine" "ers" "general_tests" "ips" "loaders" "rankings" "registrarc" "resources" "routes" "sessions" "trends")
dbtypes=("*internal" "*mysql" "*mongo" "*postgres")
# Tests that are independent of the dbtype flag and run only once
diff --git a/general_tests/offline_internal_it_test.go b/general_tests/offline_internal_it_test.go
index 4bb72ba87..48bcac667 100644
--- a/general_tests/offline_internal_it_test.go
+++ b/general_tests/offline_internal_it_test.go
@@ -319,12 +319,12 @@ func TestOfflineInternal(t *testing.T) { // run with sudo
return nil
}); err != nil {
t.Error(err)
- } else if dirs != 33 {
- t.Errorf("expected <%d> directories, received <%d>", 33, dirs)
- } else if i > 6 && files != 30 {
+ } else if dirs != 36 {
+ t.Errorf("expected <%d> directories, received <%d>", 36, dirs)
+ } else if i > 6 && files != 31 {
+ t.Errorf("expected <%d> files, received <%d>", 31, files)
+ } else if i < 6 && files != 30 {
t.Errorf("expected <%d> files, received <%d>", 30, files)
- } else if i < 6 && files != 29 {
- t.Errorf("expected <%d> files, received <%d>", 29, files)
}
})
diff --git a/general_tests/service_toggle_it_test.go b/general_tests/service_toggle_it_test.go
index aa04a259b..abfc18e24 100644
--- a/general_tests/service_toggle_it_test.go
+++ b/general_tests/service_toggle_it_test.go
@@ -186,6 +186,7 @@ func checkServiceStates(t *testing.T, client *birpc.Client, want string) {
utils.ERs,
utils.RateS,
utils.ResourceS,
+ utils.IPs,
utils.RouteS,
utils.SessionS,
utils.StatS,
diff --git a/general_tests/tut_smgeneric_it_test.go b/general_tests/tut_smgeneric_it_test.go
index c5f4253a2..976531e58 100644
--- a/general_tests/tut_smgeneric_it_test.go
+++ b/general_tests/tut_smgeneric_it_test.go
@@ -149,6 +149,8 @@ func testTutSMGCacheStats(t *testing.T) {
expectedStats[utils.CacheActionProfiles].Items = 1
expectedStats[utils.CacheResourceProfiles].Items = 1
expectedStats[utils.CacheResources].Items = 1
+ expectedStats[utils.CacheIPProfiles].Items = 1
+ expectedStats[utils.CacheIPs].Items = 1
expectedStats[utils.CacheStatQueues].Items = 7
expectedStats[utils.CacheStatQueueProfiles].Items = 7
expectedStats[utils.CacheThresholds].Items = 1
@@ -157,7 +159,7 @@ func testTutSMGCacheStats(t *testing.T) {
expectedStats[utils.CacheRouteProfiles].Items = 12
expectedStats[utils.CacheAttributeProfiles].Items = 8
expectedStats[utils.MetaDefault].Items = 0
- expectedStats[utils.CacheLoadIDs].Items = 28
+ expectedStats[utils.CacheLoadIDs].Items = 31
expectedStats[utils.CacheChargerProfiles].Items = 3
expectedStats[utils.CacheRPCConnections].Items = 1
expectedStats[utils.CacheThresholdFilterIndexes].Items = 1
@@ -168,6 +170,8 @@ func testTutSMGCacheStats(t *testing.T) {
expectedStats[utils.CacheRouteFilterIndexes].Groups = 1
expectedStats[utils.CacheResourceFilterIndexes].Items = 1
expectedStats[utils.CacheResourceFilterIndexes].Groups = 1
+ expectedStats[utils.CacheIPFilterIndexes].Items = 1
+ expectedStats[utils.CacheIPFilterIndexes].Groups = 1
expectedStats[utils.CacheChargerFilterIndexes].Items = 1
expectedStats[utils.CacheChargerFilterIndexes].Groups = 1
expectedStats[utils.CacheRankingProfiles].Items = 2
diff --git a/integration_test.sh b/integration_test.sh
index 3d41659c6..f7fa570a8 100755
--- a/integration_test.sh
+++ b/integration_test.sh
@@ -8,7 +8,7 @@
# Example:
# ./integration_test.sh -dbtype=*mysql -rpc=*gob
-packages=("agents" "apis" "attributes" "chargers" "cmd/cgr-console" "cmd/cgr-loader" "efs" "engine" "ers" "general_tests" "loaders" "rankings" "registrarc" "resources" "routes" "sessions" "trends")
+packages=("agents" "apis" "attributes" "chargers" "cmd/cgr-console" "cmd/cgr-loader" "efs" "engine" "ers" "general_tests" "ips" "loaders" "rankings" "registrarc" "resources" "routes" "sessions" "trends")
dbtypes=("*internal" "*mysql" "*mongo" "*postgres")
# Tests that are independent of the dbtype flag and run only once
diff --git a/ips/apis.go b/ips/apis.go
new file mode 100644
index 000000000..7aeef9606
--- /dev/null
+++ b/ips/apis.go
@@ -0,0 +1,327 @@
+/*
+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 ips
+
+import (
+ "time"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+ "github.com/cgrates/guardian"
+)
+
+// V1GetIPsForEvent returns active IPs matching the event.
+func (s *IPService) V1GetIPsForEvent(ctx *context.Context, args *utils.CGREvent, reply *IPs) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.UsageID,
+ utils.OptsIPsUsageID); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.TTL,
+ utils.OptsIPsTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.IPsV1GetIPsForEvent, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*IPs)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs IPs
+ if mtcRLs, err = s.matchingIPsForEvent(ctx, tnt, args, usageID, usageTTL); err != nil {
+ return err
+ }
+ *reply = mtcRLs
+ mtcRLs.unlock()
+ return
+}
+
+// V1AuthorizeIPs queries service to find if an Usage is allowed
+func (s *IPService) V1AuthorizeIPs(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.UsageID,
+ utils.OptsIPsUsageID); err != nil {
+ return
+ }
+
+ if _, err = engine.GetFloat64Opts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.Units,
+ utils.OptsIPsUnits); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.TTL,
+ utils.OptsIPsTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.IPsV1AuthorizeIPs, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*string)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs IPs
+ if mtcRLs, err = s.matchingIPsForEvent(ctx, tnt, args, usageID, usageTTL); err != nil {
+ return err
+ }
+ defer mtcRLs.unlock()
+
+ /*
+ authorize logic
+ ...
+ */
+
+ *reply = utils.OK
+ return
+}
+
+// V1AllocateIPs is called when an IP requires allocation.
+func (s *IPService) V1AllocateIPs(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.UsageID,
+ utils.OptsIPsUsageID); err != nil {
+ return
+ }
+
+ if _, err = engine.GetFloat64Opts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.Units,
+ utils.OptsIPsUnits); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.TTL,
+ utils.OptsIPsTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.IPsV1AllocateIPs, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*string)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs IPs
+ if mtcRLs, err = s.matchingIPsForEvent(ctx, tnt, args, usageID,
+ usageTTL); err != nil {
+ return err
+ }
+ defer mtcRLs.unlock()
+
+ /*
+ allocate logic
+ ...
+ */
+
+ // index it for storing
+ if err = s.storeMatchedIPs(ctx, mtcRLs); err != nil {
+ return
+ }
+ *reply = utils.OK
+ return
+}
+
+// V1ReleaseIPs is called when we need to clear an allocation
+func (s *IPService) V1ReleaseIPs(ctx *context.Context, args *utils.CGREvent, reply *string) (err error) {
+ if args == nil {
+ return utils.NewErrMandatoryIeMissing(utils.Event)
+ }
+ if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Event}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+
+ var usageID string
+ if usageID, err = engine.GetStringOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.UsageID,
+ utils.OptsIPsUsageID); err != nil {
+ return
+ }
+
+ var ttl time.Duration
+ if ttl, err = engine.GetDurationOpts(ctx, args.Tenant, args.AsDataProvider(), nil, s.fltrs, s.cfg.IPsCfg().Opts.TTL,
+ utils.OptsIPsTTL); err != nil {
+ return
+ }
+ usageTTL := utils.DurationPointer(ttl)
+
+ if usageID == utils.EmptyString {
+ return utils.NewErrMandatoryIeMissing(utils.UsageID)
+ }
+
+ tnt := args.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // RPC caching
+ if config.CgrConfig().CacheCfg().Partitions[utils.CacheRPCResponses].Limit != 0 {
+ cacheKey := utils.ConcatenatedKey(utils.IPsV1ReleaseIPs, utils.ConcatenatedKey(tnt, args.ID))
+ refID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout, cacheKey) // RPC caching needs to be atomic
+ defer guardian.Guardian.UnguardIDs(refID)
+ if itm, has := engine.Cache.Get(utils.CacheRPCResponses, cacheKey); has {
+ cachedResp := itm.(*utils.CachedRPCResponse)
+ if cachedResp.Error == nil {
+ *reply = *cachedResp.Result.(*string)
+ }
+ return cachedResp.Error
+ }
+ defer engine.Cache.Set(ctx, utils.CacheRPCResponses, cacheKey,
+ &utils.CachedRPCResponse{Result: reply, Error: err},
+ nil, true, utils.NonTransactional)
+ }
+ // end of RPC caching
+
+ var mtcRLs IPs
+ if mtcRLs, err = s.matchingIPsForEvent(ctx, tnt, args, usageID,
+ usageTTL); err != nil {
+ return
+ }
+ defer mtcRLs.unlock()
+
+ /*
+ release logic
+ ...
+ */
+
+ // Handle storing
+ if err = s.storeMatchedIPs(ctx, mtcRLs); err != nil {
+ return
+ }
+
+ *reply = utils.OK
+ return
+}
+
+// V1GetIP returns a resource configuration
+func (s *IPService) V1GetIP(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.IP) error {
+ if missing := utils.MissingStructFields(arg, []string{utils.ID}); len(missing) != 0 { //Params missing
+ return utils.NewErrMandatoryIeMissing(missing...)
+ }
+ tnt := arg.Tenant
+ if tnt == utils.EmptyString {
+ tnt = s.cfg.GeneralCfg().DefaultTenant
+ }
+
+ // make sure resource is locked at process level
+ lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.IPLockKey(tnt, arg.ID))
+ defer guardian.Guardian.UnguardIDs(lkID)
+
+ ip, err := s.dm.GetIP(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
+ if err != nil {
+ return err
+ }
+ *reply = *ip
+ return nil
+}
diff --git a/ips/ips.go b/ips/ips.go
new file mode 100644
index 000000000..c6b462877
--- /dev/null
+++ b/ips/ips.go
@@ -0,0 +1,475 @@
+/*
+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 ips
+
+import (
+ "cmp"
+ "fmt"
+ "runtime"
+ "slices"
+ "sync"
+ "time"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+ "github.com/cgrates/guardian"
+)
+
+// ipProfile represents the user configuration for the ip
+type ipProfile struct {
+ IPProfile *utils.IPProfile
+ lkID string // holds the reference towards guardian lock key
+
+}
+
+// lock will lock the ipProfile using guardian and store the lock within r.lkID
+// if lkID is passed as argument, the lock is considered as executed
+func (ip *ipProfile) lock(lkID string) {
+ if lkID == utils.EmptyString {
+ lkID = guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.IPProfileLockKey(ip.IPProfile.Tenant, ip.IPProfile.ID))
+ }
+ ip.lkID = lkID
+}
+
+// unlock will unlock the ipProfile and clear rp.lkID
+func (ip *ipProfile) unlock() {
+ if ip.lkID == utils.EmptyString {
+ return
+ }
+ guardian.Guardian.UnguardIDs(ip.lkID)
+ ip.lkID = utils.EmptyString
+}
+
+// isLocked returns the locks status of this ipProfile
+func (ip *ipProfile) isLocked() bool {
+ return ip.lkID != utils.EmptyString
+}
+
+// ip represents an ip in the system
+// not thread safe, needs locking at process level
+type ip struct {
+ IP *utils.IP
+ lkID string // ID of the lock used when matching the ip
+ ttl *time.Duration // time to leave for this ip, picked up on each IP initialization out of config
+ tUsage *float64 // sum of all usages
+ dirty *bool // the usages were modified, needs save, *bool so we only save if enabled in config
+ rPrf *ipProfile // for ordering purposes
+}
+
+// lock will lock the ip using guardian and store the lock within r.lkID
+// if lkID is passed as argument, the lock is considered as executed
+func (ip *ip) lock(lkID string) {
+ if lkID == utils.EmptyString {
+ lkID = guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.IPLockKey(ip.IP.Tenant, ip.IP.ID))
+ }
+ ip.lkID = lkID
+}
+
+// unlock will unlock the ip and clear r.lkID
+func (ip *ip) unlock() {
+ if ip.lkID == utils.EmptyString {
+ return
+ }
+ guardian.Guardian.UnguardIDs(ip.lkID)
+ ip.lkID = utils.EmptyString
+}
+
+// isLocked returns the locks status of this ip
+func (ip *ip) isLocked() bool {
+ return ip.lkID != utils.EmptyString
+}
+
+// removeExpiredUnits removes units which are expired from the ip
+func (ip *ip) removeExpiredUnits() {
+ var firstActive int
+ for _, usageID := range ip.IP.TTLIdx {
+ if u, has := ip.IP.Usages[usageID]; has && u.IsActive(time.Now()) {
+ break
+ }
+ firstActive++
+ }
+ if firstActive == 0 {
+ return
+ }
+ for _, uID := range ip.IP.TTLIdx[:firstActive] {
+ usage, has := ip.IP.Usages[uID]
+ if !has {
+ continue
+ }
+ delete(ip.IP.Usages, uID)
+ if ip.tUsage != nil { // total usage was not yet calculated so we do not need to update it
+ *ip.tUsage -= usage.Units
+ if *ip.tUsage < 0 { // something went wrong
+ utils.Logger.Warning(
+ fmt.Sprintf("resetting total usage for ipID: %s, usage smaller than 0: %f", ip.IP.ID, *ip.tUsage))
+ ip.tUsage = nil
+ }
+ }
+ }
+ ip.IP.TTLIdx = ip.IP.TTLIdx[firstActive:]
+ ip.tUsage = nil
+}
+
+// recordUsage records a new usage
+func (ip *ip) recordUsage(usage *utils.IPUsage) error {
+ if _, has := ip.IP.Usages[usage.ID]; has {
+ return fmt.Errorf("duplicate ip usage with id: %s", usage.TenantID())
+ }
+ if ip.ttl != nil && *ip.ttl != -1 {
+ if *ip.ttl == 0 {
+ return nil // no recording for ttl of 0
+ }
+ usage = usage.Clone() // don't influence the initial ru
+ usage.ExpiryTime = time.Now().Add(*ip.ttl)
+ }
+ ip.IP.Usages[usage.ID] = usage
+ if ip.tUsage != nil {
+ *ip.tUsage += usage.Units
+ }
+ if !usage.ExpiryTime.IsZero() {
+ ip.IP.TTLIdx = append(ip.IP.TTLIdx, usage.ID)
+ }
+ return nil
+}
+
+// clearUsage clears the usage for an ID
+func (ip *ip) clearUsage(usageID string) error {
+ usage, has := ip.IP.Usages[usageID]
+ if !has {
+ return fmt.Errorf("cannot find usage record with id: %s", usageID)
+ }
+ if !usage.ExpiryTime.IsZero() {
+ for i, uIDIdx := range ip.IP.TTLIdx {
+ if uIDIdx == usageID {
+ ip.IP.TTLIdx = slices.Delete(ip.IP.TTLIdx, i, i+1)
+ break
+ }
+ }
+ }
+ if ip.tUsage != nil {
+ *ip.tUsage -= usage.Units
+ }
+ delete(ip.IP.Usages, usageID)
+ return nil
+}
+
+// IPs is a collection of IP objects.
+type IPs []*ip
+
+// unlock will unlock ips part of this slice
+func (ips IPs) unlock() {
+ for _, ip := range ips {
+ ip.unlock()
+ if ip.rPrf != nil {
+ ip.rPrf.unlock()
+ }
+ }
+}
+
+// ids returns a map of ip IDs which is used for caching
+func (ips IPs) ids() utils.StringSet {
+ ids := make(utils.StringSet)
+ for _, ip := range ips {
+ ids.Add(ip.IP.ID)
+ }
+ return ids
+}
+
+// NewIPService returns a new IPService
+func NewIPService(dm *engine.DataManager, cfg *config.CGRConfig,
+ fltrs *engine.FilterS, cm *engine.ConnManager) *IPService {
+ return &IPService{dm: dm,
+ storedIPs: make(utils.StringSet),
+ cfg: cfg,
+ cm: cm,
+ fltrs: fltrs,
+ loopStopped: make(chan struct{}),
+ stopBackup: make(chan struct{}),
+ }
+
+}
+
+// IPService is the service handling resources
+type IPService struct {
+ dm *engine.DataManager // So we can load the data in cache and index it
+ fltrs *engine.FilterS
+ storedIPsMux sync.RWMutex // protects storedIPs
+ storedIPs utils.StringSet // keep a record of resources which need saving, map[resID]bool
+ cfg *config.CGRConfig
+ stopBackup chan struct{} // control storing process
+ loopStopped chan struct{}
+ cm *engine.ConnManager
+}
+
+// Reload stops the backupLoop and restarts it
+func (s *IPService) Reload(ctx *context.Context) {
+ close(s.stopBackup)
+ <-s.loopStopped // wait until the loop is done
+ s.stopBackup = make(chan struct{})
+ go s.runBackup(ctx)
+}
+
+// StartLoop starts the gorutine with the backup loop
+func (s *IPService) StartLoop(ctx *context.Context) {
+ go s.runBackup(ctx)
+}
+
+// Shutdown is called to shutdown the service
+func (s *IPService) Shutdown(ctx *context.Context) {
+ close(s.stopBackup)
+ s.storeIPs(ctx)
+}
+
+// backup will regularly store resources changed to dataDB
+func (s *IPService) runBackup(ctx *context.Context) {
+ storeInterval := s.cfg.IPsCfg().StoreInterval
+ if storeInterval <= 0 {
+ s.loopStopped <- struct{}{}
+ return
+ }
+ for {
+ s.storeIPs(ctx)
+ select {
+ case <-s.stopBackup:
+ s.loopStopped <- struct{}{}
+ return
+ case <-time.After(storeInterval):
+ }
+ }
+}
+
+// storeIPs represents one task of complete backup
+func (s *IPService) storeIPs(ctx *context.Context) {
+ var failedRIDs []string
+ for { // don't stop until we store all dirty resources
+ s.storedIPsMux.Lock()
+ rID := s.storedIPs.GetOne()
+ if rID != "" {
+ s.storedIPs.Remove(rID)
+ }
+ s.storedIPsMux.Unlock()
+ if rID == "" {
+ break // no more keys, backup completed
+ }
+ rIf, ok := engine.Cache.Get(utils.CacheIPs, rID)
+ if !ok || rIf == nil {
+ utils.Logger.Warning(fmt.Sprintf("<%s> failed retrieving from cache resource with ID: %s", utils.IPs, rID))
+ continue
+ }
+ r := &ip{
+ IP: rIf.(*utils.IP),
+
+ // NOTE: dirty is hardcoded to true, otherwise resources would
+ // never be stored.
+ // Previously, dirty was part of the cached resource.
+ dirty: utils.BoolPointer(true),
+ }
+ r.lock(utils.EmptyString)
+ if err := s.storeIP(ctx, r); err != nil {
+ failedRIDs = append(failedRIDs, rID) // record failure so we can schedule it for next backup
+ }
+ r.unlock()
+ // randomize the CPU load and give up thread control
+ runtime.Gosched()
+ }
+ if len(failedRIDs) != 0 { // there were errors on save, schedule the keys for next backup
+ s.storedIPsMux.Lock()
+ s.storedIPs.AddSlice(failedRIDs)
+ s.storedIPsMux.Unlock()
+ }
+}
+
+// StoreIP stores the resource in DB and corrects dirty flag
+func (s *IPService) storeIP(ctx *context.Context, r *ip) (err error) {
+ if r.dirty == nil || !*r.dirty {
+ return
+ }
+ if err = s.dm.SetIP(ctx, r.IP); err != nil {
+ utils.Logger.Warning(
+ fmt.Sprintf(" failed saving IP with ID: %s, error: %s",
+ r.IP.ID, err.Error()))
+ return
+ }
+ //since we no longer handle cache in DataManager do here a manual caching
+ if tntID := r.IP.TenantID(); engine.Cache.HasItem(utils.CacheIPs, tntID) { // only cache if previously there
+ if err = engine.Cache.Set(ctx, utils.CacheIPs, tntID, r.IP, nil,
+ true, utils.NonTransactional); err != nil {
+ utils.Logger.Warning(
+ fmt.Sprintf(" failed caching IP with ID: %s, error: %s",
+ tntID, err.Error()))
+ return
+ }
+ }
+ *r.dirty = false
+ return
+}
+
+// storeMatchedIPs will store the list of resources based on the StoreInterval
+func (s *IPService) storeMatchedIPs(ctx *context.Context, mtcRLs IPs) (err error) {
+ if s.cfg.IPsCfg().StoreInterval == 0 {
+ return
+ }
+ if s.cfg.IPsCfg().StoreInterval > 0 {
+ s.storedIPsMux.Lock()
+ defer s.storedIPsMux.Unlock()
+ }
+ for _, r := range mtcRLs {
+ if r.dirty != nil {
+ *r.dirty = true // mark it to be saved
+ if s.cfg.IPsCfg().StoreInterval > 0 {
+ s.storedIPs.Add(r.IP.TenantID())
+ continue
+ }
+ if err = s.storeIP(ctx, r); err != nil {
+ return
+ }
+ }
+
+ }
+ return
+}
+
+// matchingIPsForEvent returns ordered list of matching resources which are active by the time of the call
+func (s *IPService) matchingIPsForEvent(ctx *context.Context, tnt string, ev *utils.CGREvent,
+ evUUID string, ttl *time.Duration) (ips IPs, err error) {
+ var rIDs utils.StringSet
+ evNm := utils.MapStorage{
+ utils.MetaReq: ev.Event,
+ utils.MetaOpts: ev.APIOpts,
+ }
+ if x, ok := engine.Cache.Get(utils.CacheEventIPs, evUUID); ok { // The IPIDs were cached as utils.StringSet{"resID":bool}
+ if x == nil {
+ return nil, utils.ErrNotFound
+ }
+ rIDs = x.(utils.StringSet)
+ defer func() { // make sure we uncache if we find errors
+ if err != nil {
+ // TODO: Consider using RemoveWithoutReplicate instead, as
+ // partitions with Replicate=true call ReplicateRemove in
+ // onEvict by default.
+ if errCh := engine.Cache.Remove(ctx, utils.CacheEventIPs, evUUID,
+ true, utils.NonTransactional); errCh != nil {
+ err = errCh
+ }
+ }
+ }()
+
+ } else { // select the resourceIDs out of dataDB
+ rIDs, err = engine.MatchingItemIDsForEvent(ctx, evNm,
+ s.cfg.IPsCfg().StringIndexedFields,
+ s.cfg.IPsCfg().PrefixIndexedFields,
+ s.cfg.IPsCfg().SuffixIndexedFields,
+ s.cfg.IPsCfg().ExistsIndexedFields,
+ s.cfg.IPsCfg().NotExistsIndexedFields,
+ s.dm, utils.CacheIPFilterIndexes, tnt,
+ s.cfg.IPsCfg().IndexedSelects,
+ s.cfg.IPsCfg().NestedFields,
+ )
+ if err != nil {
+ if err == utils.ErrNotFound {
+ if errCh := engine.Cache.Set(ctx, utils.CacheEventIPs, evUUID, nil, nil, true, ""); errCh != nil { // cache negative match
+ return nil, errCh
+ }
+ }
+ return
+ }
+ }
+ ips = make(IPs, 0, len(rIDs))
+ weights := make(map[string]float64) // stores sorting weights by resource ID
+ for resName := range rIDs {
+ lkPrflID := guardian.Guardian.GuardIDs("",
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.IPProfileLockKey(tnt, resName))
+ var rp *utils.IPProfile
+ if rp, err = s.dm.GetIPProfile(ctx, tnt, resName,
+ true, true, utils.NonTransactional); err != nil {
+ guardian.Guardian.UnguardIDs(lkPrflID)
+ if err == utils.ErrNotFound {
+ continue
+ }
+ ips.unlock()
+ return
+ }
+ rPrf := &ipProfile{
+ IPProfile: rp,
+ }
+ rPrf.lock(lkPrflID)
+ var pass bool
+ if pass, err = s.fltrs.Pass(ctx, tnt, rPrf.IPProfile.FilterIDs,
+ evNm); err != nil {
+ rPrf.unlock()
+ ips.unlock()
+ return nil, err
+ } else if !pass {
+ rPrf.unlock()
+ continue
+ }
+ lkID := guardian.Guardian.GuardIDs(utils.EmptyString,
+ config.CgrConfig().GeneralCfg().LockingTimeout,
+ utils.IPLockKey(rPrf.IPProfile.Tenant, rPrf.IPProfile.ID))
+ var res *utils.IP
+ if res, err = s.dm.GetIP(ctx, rPrf.IPProfile.Tenant, rPrf.IPProfile.ID, true, true, ""); err != nil {
+ guardian.Guardian.UnguardIDs(lkID)
+ rPrf.unlock()
+ ips.unlock()
+ return nil, err
+ }
+ r := &ip{
+ IP: res,
+ }
+ r.lock(lkID) // pass the lock into resource so we have it as reference
+ if rPrf.IPProfile.Stored && r.dirty == nil {
+ r.dirty = utils.BoolPointer(false)
+ }
+ if ttl != nil {
+ if *ttl != 0 {
+ r.ttl = ttl
+ }
+ } else if rPrf.IPProfile.TTL >= 0 {
+ r.ttl = utils.DurationPointer(rPrf.IPProfile.TTL)
+ }
+ r.rPrf = rPrf
+ weight, err := engine.WeightFromDynamics(ctx, rPrf.IPProfile.Weights, s.fltrs, tnt, evNm)
+ if err != nil {
+ return nil, err
+ }
+ weights[r.IP.ID] = weight
+ ips = append(ips, r)
+ }
+
+ if len(ips) == 0 {
+ return nil, utils.ErrNotFound
+ }
+
+ // Sort by weight (higher values first).
+ slices.SortFunc(ips, func(a, b *ip) int {
+ return cmp.Compare(weights[b.IP.ID], weights[a.IP.ID])
+ })
+
+ if err = engine.Cache.Set(ctx, utils.CacheEventIPs, evUUID, ips.ids(), nil, true, ""); err != nil {
+ ips.unlock()
+ }
+ return
+}
diff --git a/loaders/libloader.go b/loaders/libloader.go
index 61eee2447..0172b6c9e 100644
--- a/loaders/libloader.go
+++ b/loaders/libloader.go
@@ -270,6 +270,10 @@ func newProfileFunc(lType string) func() profile {
return func() profile {
return new(utils.ResourceProfile)
}
+ case utils.MetaIPs:
+ return func() profile {
+ return new(utils.IPProfile)
+ }
case utils.MetaFilters:
return func() profile {
return new(engine.Filter)
diff --git a/loaders/loader.go b/loaders/loader.go
index 3ac5dc8f4..8c0008405 100644
--- a/loaders/loader.go
+++ b/loaders/loader.go
@@ -45,6 +45,8 @@ func removeFromDB(ctx *context.Context, dm *engine.DataManager, lType string, wi
return dm.RemoveAttributeProfile(ctx, tnt, id, withIndex)
case utils.MetaResources:
return dm.RemoveResourceProfile(ctx, tnt, id, withIndex)
+ case utils.MetaIPs:
+ return dm.RemoveIPProfile(ctx, tnt, id, withIndex)
case utils.MetaFilters:
return dm.RemoveFilter(ctx, tnt, id, withIndex)
case utils.MetaStats:
@@ -83,6 +85,8 @@ func setToDB(ctx *context.Context, dm *engine.DataManager, lType string, data pr
return dm.SetAttributeProfile(ctx, data.(*utils.AttributeProfile), withIndex)
case utils.MetaResources:
return dm.SetResourceProfile(ctx, data.(*utils.ResourceProfile), withIndex)
+ case utils.MetaIPs:
+ return dm.SetIPProfile(ctx, data.(*utils.IPProfile), withIndex)
case utils.MetaFilters:
fltr := data.(*engine.Filter)
fltr.Compress()
@@ -124,6 +128,8 @@ func dryRun(ctx *context.Context, lType, ldrID string, obj profile) (err error)
msg = "<%s-%s> DRY_RUN: AttributeProfile: %s"
case utils.MetaResources:
msg = "<%s-%s> DRY_RUN: ResourceProfile: %s"
+ case utils.MetaIPs:
+ msg = "<%s-%s> DRY_RUN: IPProfile: %s"
case utils.MetaFilters:
fltr := obj.(*engine.Filter)
fltr.Compress()
@@ -208,6 +214,10 @@ func (l *loader) process(ctx *context.Context, obj profile, lType, action string
cacheIDs = []string{utils.CacheResourceFilterIndexes}
cacheArgs[utils.CacheResourceProfiles] = []string{tntId}
cacheArgs[utils.CacheResources] = []string{tntId}
+ case utils.MetaIPs:
+ cacheIDs = []string{utils.CacheIPFilterIndexes}
+ cacheArgs[utils.CacheIPProfiles] = []string{tntId}
+ cacheArgs[utils.CacheIPs] = []string{tntId}
case utils.MetaFilters:
cacheArgs[utils.CacheFilters] = []string{tntId}
case utils.MetaStats:
diff --git a/services/commonlisteners.go b/services/commonlisteners.go
index 514dff9e3..2cc4b6571 100644
--- a/services/commonlisteners.go
+++ b/services/commonlisteners.go
@@ -92,6 +92,7 @@ func (s *CommonListenerService) Shutdown(registry *servmanager.ServiceRegistry)
utils.RateS,
utils.RegistrarC,
utils.ResourceS,
+ utils.IPs,
utils.RouteS,
utils.SessionS,
utils.StatS,
diff --git a/services/connmanager.go b/services/connmanager.go
index 5ddf85ce0..2912d7dd5 100644
--- a/services/connmanager.go
+++ b/services/connmanager.go
@@ -149,6 +149,10 @@ var serviceMethods = map[string]internalRoute{
receiver: utils.ResourceSv1,
internalPath: utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources),
},
+ utils.IPs: {
+ receiver: utils.IPsV1,
+ internalPath: utils.ConcatenatedKey(utils.MetaInternal, utils.MetaIPs),
+ },
utils.SessionS: {
receiver: utils.SessionSv1,
internalPath: utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS),
diff --git a/services/datadb.go b/services/datadb.go
index 7bd5ca86e..224346255 100644
--- a/services/datadb.go
+++ b/services/datadb.go
@@ -112,6 +112,7 @@ func (db *DataDBService) Reload(_ *utils.SyncedChan, _ *servmanager.ServiceRegis
func (db *DataDBService) Shutdown(registry *servmanager.ServiceRegistry) error {
deps := []string{
utils.ResourceS,
+ utils.IPs,
utils.TrendS,
utils.RankingS,
utils.StatS,
diff --git a/services/ips.go b/services/ips.go
new file mode 100644
index 000000000..8e50aba17
--- /dev/null
+++ b/services/ips.go
@@ -0,0 +1,121 @@
+/*
+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 services
+
+import (
+ "sync"
+
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/ips"
+ "github.com/cgrates/cgrates/servmanager"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// NewIPService returns the IP Service
+func NewIPService(cfg *config.CGRConfig) *IPService {
+ return &IPService{
+ cfg: cfg,
+ stateDeps: NewStateDependencies([]string{utils.StateServiceUP, utils.StateServiceDOWN}),
+ }
+}
+
+// IPService implements Service interface
+type IPService struct {
+ mu sync.RWMutex
+ cfg *config.CGRConfig
+ ips *ips.IPService
+ stateDeps *StateDependencies // channel subscriptions for state changes
+}
+
+// Start handles the service start.
+func (s *IPService) Start(shutdown *utils.SyncedChan, registry *servmanager.ServiceRegistry) error {
+ srvDeps, err := WaitForServicesToReachState(utils.StateServiceUP,
+ []string{
+ utils.CommonListenerS,
+ utils.ConnManager,
+ utils.CacheS,
+ utils.FilterS,
+ utils.DataDB,
+ },
+ registry, s.cfg.GeneralCfg().ConnectTimeout)
+ if err != nil {
+ return err
+ }
+ cl := srvDeps[utils.CommonListenerS].(*CommonListenerService).CLS()
+ cms := srvDeps[utils.ConnManager].(*ConnManagerService)
+ cacheS := srvDeps[utils.CacheS].(*CacheService)
+ if err := cacheS.WaitToPrecache(shutdown,
+ utils.CacheIPProfiles,
+ utils.CacheIPs,
+ utils.CacheIPFilterIndexes); err != nil {
+ return err
+ }
+ fs := srvDeps[utils.FilterS].(*FilterService)
+ dbs := srvDeps[utils.DataDB].(*DataDBService)
+
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.ips = ips.NewIPService(dbs.DataManager(), s.cfg, fs.FilterS(), cms.ConnManager())
+ s.ips.StartLoop(context.TODO())
+ srv, err := engine.NewService(s.ips)
+ if err != nil {
+ return err
+ }
+ for _, svc := range srv {
+ cl.RpcRegister(svc)
+ }
+ cms.AddInternalConn(utils.IPs, srv)
+ return nil
+}
+
+// Reload handles configuration changes.
+func (s *IPService) Reload(_ *utils.SyncedChan, _ *servmanager.ServiceRegistry) error {
+ s.mu.Lock()
+ s.ips.Reload(context.TODO())
+ s.mu.Unlock()
+ return nil
+}
+
+// Shutdown stops the service.
+func (s *IPService) Shutdown(registry *servmanager.ServiceRegistry) error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.ips.Shutdown(context.TODO()) //we don't verify the error because shutdown never returns an error
+ s.ips = nil
+ cl := registry.Lookup(utils.CommonListenerS).(*CommonListenerService).CLS()
+ cl.RpcUnregisterName(utils.IPsV1)
+ return nil
+}
+
+// ServiceName returns the service name.
+func (s *IPService) ServiceName() string {
+ return utils.IPs
+}
+
+// ShouldRun returns if the service should be running.
+func (s *IPService) ShouldRun() bool {
+ return s.cfg.IPsCfg().Enabled
+}
+
+// StateChan returns signaling channel of specific state
+func (s *IPService) StateChan(stateID string) chan struct{} {
+ return s.stateDeps.StateChan(stateID)
+}
diff --git a/services/prometheus.go b/services/prometheus.go
index 8775514cf..7a62592d8 100644
--- a/services/prometheus.go
+++ b/services/prometheus.go
@@ -35,7 +35,7 @@ func NewPrometheusAgent(cfg *config.CGRConfig) *PrometheusAgent {
}
}
-// PrometheusAgent implements Agent interface
+// PrometheusAgent implements the Service interface.
type PrometheusAgent struct {
mu sync.RWMutex
cfg *config.CGRConfig
@@ -43,7 +43,7 @@ type PrometheusAgent struct {
stateDeps *StateDependencies
}
-// Start should handle the sercive start
+// Start handles the service start.
func (s *PrometheusAgent) Start(_ *utils.SyncedChan, registry *servmanager.ServiceRegistry) (err error) {
srvDeps, err := WaitForServicesToReachState(utils.StateServiceUP,
[]string{
diff --git a/servmanager/servmanager.go b/servmanager/servmanager.go
index 3725bf81e..157dc07f4 100644
--- a/servmanager/servmanager.go
+++ b/servmanager/servmanager.go
@@ -264,6 +264,9 @@ func toggleService(id string, status bool, srvMngr *ServiceManager) (err error)
case utils.ResourceS:
srvMngr.cfg.ResourceSCfg().Enabled = status
srvMngr.cfg.GetReloadChan() <- id
+ case utils.IPs:
+ srvMngr.cfg.IPsCfg().Enabled = status
+ srvMngr.cfg.GetReloadChan() <- id
case utils.RouteS:
srvMngr.cfg.RouteSCfg().Enabled = status
srvMngr.cfg.GetReloadChan() <- id
diff --git a/utils/apitpdata.go b/utils/apitpdata.go
index c20230a64..889832b42 100644
--- a/utils/apitpdata.go
+++ b/utils/apitpdata.go
@@ -402,6 +402,8 @@ func NewAttrReloadCacheWithOpts() *AttrReloadCacheWithAPIOpts {
return &AttrReloadCacheWithAPIOpts{
ResourceProfileIDs: []string{MetaAny},
ResourceIDs: []string{MetaAny},
+ IPProfileIDs: []string{MetaAny},
+ IPIDs: []string{MetaAny},
StatsQueueIDs: []string{MetaAny},
StatsQueueProfileIDs: []string{MetaAny},
ThresholdIDs: []string{MetaAny},
@@ -420,6 +422,7 @@ func NewAttrReloadCacheWithOpts() *AttrReloadCacheWithAPIOpts {
AttributeFilterIndexIDs: []string{MetaAny},
ResourceFilterIndexIDs: []string{MetaAny},
+ IPFilterIndexIDs: []string{MetaAny},
StatFilterIndexIDs: []string{MetaAny},
ThresholdFilterIndexIDs: []string{MetaAny},
RouteFilterIndexIDs: []string{MetaAny},
@@ -439,6 +442,8 @@ func NewAttrReloadCacheWithOptsFromMap(arg map[string][]string, tnt string, opts
ResourceProfileIDs: arg[CacheResourceProfiles],
ResourceIDs: arg[CacheResources],
+ IPProfileIDs: arg[CacheIPProfiles],
+ IPIDs: arg[CacheIPs],
StatsQueueProfileIDs: arg[CacheStatQueueProfiles],
StatsQueueIDs: arg[CacheStatQueues],
ThresholdProfileIDs: arg[CacheThresholdProfiles],
@@ -453,6 +458,7 @@ func NewAttrReloadCacheWithOptsFromMap(arg map[string][]string, tnt string, opts
ActionProfileIDs: arg[CacheActionProfiles],
AccountIDs: arg[CacheAccounts],
ResourceFilterIndexIDs: arg[CacheResourceFilterIndexes],
+ IPFilterIndexIDs: arg[CacheIPFilterIndexes],
StatFilterIndexIDs: arg[CacheStatFilterIndexes],
ThresholdFilterIndexIDs: arg[CacheThresholdFilterIndexes],
RouteFilterIndexIDs: arg[CacheRouteFilterIndexes],
@@ -474,6 +480,8 @@ type AttrReloadCacheWithAPIOpts struct {
ResourceProfileIDs []string `json:",omitempty"`
ResourceIDs []string `json:",omitempty"`
+ IPProfileIDs []string `json:",omitempty"`
+ IPIDs []string `json:",omitempty"`
StatsQueueIDs []string `json:",omitempty"`
StatsQueueProfileIDs []string `json:",omitempty"`
ThresholdIDs []string `json:",omitempty"`
@@ -492,6 +500,7 @@ type AttrReloadCacheWithAPIOpts struct {
AttributeFilterIndexIDs []string `json:",omitempty"`
ResourceFilterIndexIDs []string `json:",omitempty"`
+ IPFilterIndexIDs []string `json:",omitempty"`
StatFilterIndexIDs []string `json:",omitempty"`
ThresholdFilterIndexIDs []string `json:",omitempty"`
RouteFilterIndexIDs []string `json:",omitempty"`
@@ -507,6 +516,8 @@ func (a *AttrReloadCacheWithAPIOpts) Map() map[string][]string {
return map[string][]string{
CacheResourceProfiles: a.ResourceProfileIDs,
CacheResources: a.ResourceIDs,
+ CacheIPProfiles: a.IPProfileIDs,
+ CacheIPs: a.IPIDs,
CacheStatQueueProfiles: a.StatsQueueProfileIDs,
CacheStatQueues: a.StatsQueueIDs,
CacheThresholdProfiles: a.ThresholdProfileIDs,
@@ -523,6 +534,7 @@ func (a *AttrReloadCacheWithAPIOpts) Map() map[string][]string {
CacheActionProfiles: a.ActionProfileIDs,
CacheAccounts: a.AccountIDs,
CacheResourceFilterIndexes: a.ResourceFilterIndexIDs,
+ CacheIPFilterIndexes: a.IPFilterIndexIDs,
CacheStatFilterIndexes: a.StatFilterIndexIDs,
CacheThresholdFilterIndexes: a.ThresholdFilterIndexIDs,
CacheRouteFilterIndexes: a.RouteFilterIndexIDs,
diff --git a/utils/apitpdata_test.go b/utils/apitpdata_test.go
index d31d85f02..2a5de734f 100644
--- a/utils/apitpdata_test.go
+++ b/utils/apitpdata_test.go
@@ -114,6 +114,8 @@ func TestNewAttrReloadCacheWithOpts(t *testing.T) {
newAttrReloadCache := &AttrReloadCacheWithAPIOpts{
ResourceProfileIDs: []string{MetaAny},
ResourceIDs: []string{MetaAny},
+ IPProfileIDs: []string{MetaAny},
+ IPIDs: []string{MetaAny},
StatsQueueIDs: []string{MetaAny},
StatsQueueProfileIDs: []string{MetaAny},
ThresholdIDs: []string{MetaAny},
@@ -127,6 +129,7 @@ func TestNewAttrReloadCacheWithOpts(t *testing.T) {
RateProfileIDs: []string{MetaAny},
AttributeFilterIndexIDs: []string{MetaAny},
ResourceFilterIndexIDs: []string{MetaAny},
+ IPFilterIndexIDs: []string{MetaAny},
StatFilterIndexIDs: []string{MetaAny},
ThresholdFilterIndexIDs: []string{MetaAny},
RouteFilterIndexIDs: []string{MetaAny},
diff --git a/utils/consts.go b/utils/consts.go
index 6592840c9..58471729a 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -37,14 +37,16 @@ var (
CacheCapsEvents, CacheReplicationHosts})
DataDBPartitions = NewStringSet([]string{
- CacheResourceProfiles, CacheResources, CacheEventResources, CacheStatQueueProfiles, CacheStatQueues,
- CacheThresholdProfiles, CacheThresholds, CacheFilters, CacheRouteProfiles, CacheAttributeProfiles, CacheTrendProfiles,
- CacheChargerProfiles, CacheActionProfiles, CacheRankingProfiles, CacheRankings, CacheTrends,
- CacheResourceFilterIndexes, CacheStatFilterIndexes, CacheThresholdFilterIndexes, CacheRouteFilterIndexes,
- CacheAttributeFilterIndexes, CacheChargerFilterIndexes, CacheLoadIDs,
- CacheRateProfiles, CacheRateProfilesFilterIndexes, CacheRateFilterIndexes,
- CacheActionProfilesFilterIndexes, CacheAccountsFilterIndexes, CacheReverseFilterIndexes,
- CacheAccounts})
+ CacheResourceProfiles, CacheResources, CacheEventResources, CacheIPProfiles, CacheIPs,
+ CacheEventIPs, CacheStatQueueProfiles, CacheStatQueues, CacheThresholdProfiles,
+ CacheThresholds, CacheFilters, CacheRouteProfiles, CacheAttributeProfiles,
+ CacheTrendProfiles, CacheChargerProfiles, CacheActionProfiles, CacheRankingProfiles,
+ CacheRankings, CacheTrends, CacheResourceFilterIndexes, CacheIPFilterIndexes, CacheStatFilterIndexes,
+ CacheThresholdFilterIndexes, CacheRouteFilterIndexes, CacheAttributeFilterIndexes,
+ CacheChargerFilterIndexes, CacheLoadIDs, CacheRateProfiles, CacheRateProfilesFilterIndexes,
+ CacheRateFilterIndexes, CacheActionProfilesFilterIndexes, CacheAccountsFilterIndexes,
+ CacheReverseFilterIndexes, CacheAccounts,
+ })
// CachePartitions enables creation of cache partitions
CachePartitions = JoinStringSet(extraDBPartition, DataDBPartitions)
@@ -52,6 +54,8 @@ var (
CacheInstanceToPrefix = map[string]string{
CacheResourceProfiles: ResourceProfilesPrefix,
CacheResources: ResourcesPrefix,
+ CacheIPProfiles: IPProfilesPrefix,
+ CacheIPs: IPsPrefix,
CacheStatQueueProfiles: StatQueueProfilePrefix,
CacheStatQueues: StatQueuePrefix,
CacheTrendProfiles: TrendProfilePrefix,
@@ -68,6 +72,7 @@ var (
CacheActionProfiles: ActionProfilePrefix,
CacheAccounts: AccountPrefix,
CacheResourceFilterIndexes: ResourceFilterIndexes,
+ CacheIPFilterIndexes: IPFilterIndexes,
CacheStatFilterIndexes: StatFilterIndexes,
CacheThresholdFilterIndexes: ThresholdFilterIndexes,
CacheRouteFilterIndexes: RouteFilterIndexes,
@@ -86,6 +91,7 @@ var (
CacheIndexesToPrefix = map[string]string{ // used by match index to get all the ids when index selects is disabled and for compute indexes
CacheThresholdFilterIndexes: ThresholdProfilePrefix,
CacheResourceFilterIndexes: ResourceProfilesPrefix,
+ CacheIPFilterIndexes: IPProfilesPrefix,
CacheStatFilterIndexes: StatQueueProfilePrefix,
CacheRouteFilterIndexes: RouteProfilePrefix,
CacheAttributeFilterIndexes: AttributeProfilePrefix,
@@ -99,6 +105,7 @@ var (
CacheInstanceToCacheIndex = map[string]string{
CacheThresholdProfiles: CacheThresholdFilterIndexes,
CacheResourceProfiles: CacheResourceFilterIndexes,
+ CacheIPProfiles: CacheIPFilterIndexes,
CacheStatQueueProfiles: CacheStatFilterIndexes,
CacheRouteProfiles: CacheRouteFilterIndexes,
CacheAttributeProfiles: CacheAttributeFilterIndexes,
@@ -244,6 +251,8 @@ const (
ConfigPrefix = "cfg_"
ResourcesPrefix = "res_"
ResourceProfilesPrefix = "rsp_"
+ IPsPrefix = "ips_"
+ IPProfilesPrefix = "ipp_"
ThresholdPrefix = "thd_"
FilterPrefix = "ftr_"
CDRsStatsPrefix = "cst_"
@@ -407,6 +416,7 @@ const (
RatingProfiles = "RatingProfiles"
AccountActions = "AccountActions"
ResourcesStr = "Resources"
+ IPsStr = "IPs"
Stats = "Stats"
Rankings = "Rankings"
Trends = "Trends"
@@ -455,6 +465,7 @@ const (
AccountID = "AccountID"
AccountIDs = "AccountIDs"
ResourceID = "ResourceID"
+ IPID = "IPID"
TotalUsage = "TotalUsage"
StatID = "StatID"
BalanceType = "BalanceType"
@@ -485,6 +496,7 @@ const (
SessionSCosts = "SessionSCosts"
RQF = "RQF"
ResourceStr = "Resource"
+ IPStr = "IP"
User = "User"
Subscribers = "Subscribers"
//Destinations = "Destinations"
@@ -501,6 +513,8 @@ const (
Limit = "Limit"
UsageTTL = "UsageTTL"
AllocationMessage = "AllocationMessage"
+ AddressPool = "AddressPool"
+ Allocation = "Allocation"
Stored = "Stored"
RatingSubject = "RatingSubject"
Categories = "Categories"
@@ -664,6 +678,7 @@ const (
VersionName = "Version"
MetaTenant = "*tenant"
ResourceUsageStr = "ResourceUsage"
+ IPUsageStr = "IPUsage"
MetaDuration = "*duration"
MetaLibPhoneNumber = "*libphonenumber"
MetaTimeString = "*time_string"
@@ -975,6 +990,7 @@ const (
MetaAccounts = "*accounts"
MetaActions = "*actions"
MetaResourceProfile = "*resource_profiles"
+ MetaIPProfiles = "*ip_profiles"
MetaStatQueueProfiles = "*statqueue_profiles"
MetaStatQueues = "*statqueues"
MetaRankingProfiles = "*ranking_profiles"
@@ -1014,6 +1030,7 @@ const (
AttributeS = "AttributeS"
RouteS = "RouteS"
ResourceS = "ResourceS"
+ IPs = "IPs"
StatService = "StatS"
FilterS = "FilterS"
ThresholdS = "ThresholdS"
@@ -1041,6 +1058,7 @@ const (
ChargerSLow = "chargers"
RoutesLow = "routes"
ResourcesLow = "resources"
+ IPsLow = "ips"
StatServiceLow = "stats"
ThresholdsLow = "thresholds"
AnalyzerSLow = "analyzers"
@@ -1097,6 +1115,7 @@ const (
MetaTpActionProfiles = "*tp_action_profiles"
MetaTpRateProfiles = "*tp_rate_profiles"
MetaTpResources = "*tp_resources"
+ MetaTpIPs = "*tp_ips"
MetaTpChargers = "*tp_chargers"
MetaDurationSeconds = "*duration_seconds"
MetaDurationNanoseconds = "*duration_nanoseconds"
@@ -1117,6 +1136,8 @@ const (
TpStats = "TpStats"
TpResources = "TpResources"
TpResource = "TpResource"
+ TpIPs = "TpIPs"
+ TpIP = "TpIP"
TpChargers = "TpChargers"
TpRateProfiles = "TpRateProfiles"
TpActionProfiles = "TpActionProfiles"
@@ -1135,6 +1156,7 @@ const (
RankingSv1 = "RankingSv1"
StatSv1 = "StatSv1"
ResourceSv1 = "ResourceSv1"
+ IPsV1 = "IPsV1"
RouteSv1 = "RouteSv1"
AttributeSv1 = "AttributeSv1"
SessionSv1 = "SessionSv1"
@@ -1162,6 +1184,7 @@ const (
MetaGreaterThan = "*gt"
MetaGreaterOrEqual = "*gte"
MetaResources = "*resources"
+ MetaIPs = "*ips"
MetaEqual = "*eq"
MetaIPNet = "*ipnet"
MetaAPIBan = "*apiban"
@@ -1210,6 +1233,8 @@ const (
ReplicatorSv1GetTrend = "ReplicatorSv1.GetTrend"
ReplicatorSv1GetResource = "ReplicatorSv1.GetResource"
ReplicatorSv1GetResourceProfile = "ReplicatorSv1.GetResourceProfile"
+ ReplicatorSv1GetIP = "ReplicatorSv1.GetIP"
+ ReplicatorSv1GetIPProfile = "ReplicatorSv1.GetIPProfile"
ReplicatorSv1GetRouteProfile = "ReplicatorSv1.GetRouteProfile"
ReplicatorSv1GetAttributeProfile = "ReplicatorSv1.GetAttributeProfile"
ReplicatorSv1GetChargerProfile = "ReplicatorSv1.GetChargerProfile"
@@ -1230,6 +1255,8 @@ const (
ReplicatorSv1SetTrend
ReplicatorSv1SetResource = "ReplicatorSv1.SetResource"
ReplicatorSv1SetResourceProfile = "ReplicatorSv1.SetResourceProfile"
+ ReplicatorSv1SetIP = "ReplicatorSv1.SetIP"
+ ReplicatorSv1SetIPProfile = "ReplicatorSv1.SetIPProfile"
ReplicatorSv1SetRouteProfile = "ReplicatorSv1.SetRouteProfile"
ReplicatorSv1SetAttributeProfile = "ReplicatorSv1.SetAttributeProfile"
ReplicatorSv1SetChargerProfile = "ReplicatorSv1.SetChargerProfile"
@@ -1249,6 +1276,8 @@ const (
ReplicatorSv1RemoveTrend = "ReplicatorSv1.RemoveTrend"
ReplicatorSv1RemoveResource = "ReplicatorSv1.RemoveResource"
ReplicatorSv1RemoveResourceProfile = "ReplicatorSv1.RemoveResourceProfile"
+ ReplicatorSv1RemoveIP = "ReplicatorSv1.RemoveIP"
+ ReplicatorSv1RemoveIPProfile = "ReplicatorSv1.RemoveIPProfile"
ReplicatorSv1RemoveRouteProfile = "ReplicatorSv1.RemoveRouteProfile"
ReplicatorSv1RemoveAttributeProfile = "ReplicatorSv1.RemoveAttributeProfile"
ReplicatorSv1RemoveChargerProfile = "ReplicatorSv1.RemoveChargerProfile"
@@ -1278,6 +1307,7 @@ const (
AdminSv1GetReverseFilterHealth = "AdminSv1.GetReverseFilterHealth"
AdminSv1GetThresholdsIndexesHealth = "AdminSv1.GetThresholdsIndexesHealth"
AdminSv1GetResourcesIndexesHealth = "AdminSv1.GetResourcesIndexesHealth"
+ AdminSv1GetIPsIndexesHealth = "AdminSv1.GetIPsIndexesHealth"
AdminSv1GetStatsIndexesHealth = "AdminSv1.GetStatsIndexesHealth"
AdminSv1GetRoutesIndexesHealth = "AdminSv1.GetRoutesIndexesHealth"
AdminSv1GetChargersIndexesHealth = "AdminSv1.GetChargersIndexesHealth"
@@ -1584,6 +1614,24 @@ const (
AdminSv1GetResourceProfilesCount = "AdminSv1.GetResourceProfilesCount"
)
+// IPs APIs
+const (
+ IPsV1AuthorizeIPs = "IPsV1.AuthorizeIPs"
+ IPsV1GetIPsForEvent = "IPsV1.GetIPsForEvent"
+ IPsV1AllocateIPs = "IPsV1.AllocateIPs"
+ IPsV1ReleaseIPs = "IPsV1.ReleaseIPs"
+ IPsV1Ping = "IPsV1.Ping"
+ IPsV1GetIPWithConfig = "IPsV1.GetIPWithConfig"
+ IPsV1GetIP = "IPsV1.GetIP"
+ IPsV1GetIPs = "IPsV1.GetIPs"
+ AdminSv1SetIPProfile = "AdminSv1.SetIPProfile"
+ AdminSv1GetIPProfiles = "AdminSv1.GetIPProfiles"
+ AdminSv1RemoveIPProfile = "AdminSv1.RemoveIPProfile"
+ AdminSv1GetIPProfile = "AdminSv1.GetIPProfile"
+ AdminSv1GetIPProfileIDs = "AdminSv1.GetIPProfileIDs"
+ AdminSv1GetIPProfilesCount = "AdminSv1.GetIPProfilesCount"
+)
+
// SessionS APIs
const (
SessionSv1AuthorizeEvent = "SessionSv1.AuthorizeEvent"
@@ -1762,6 +1810,7 @@ const (
// CSV file name
const (
ResourcesCsv = "Resources.csv"
+ IPsCsv = "IPs.csv"
StatsCsv = "Stats.csv"
RankingsCsv = "Rankings.csv"
TrendsCsv = "Trends.csv"
@@ -1778,6 +1827,7 @@ const (
// Table Name
const (
TBLTPResources = "tp_resources"
+ TBLTPIPs = "tp_ips"
TBLTPStats = "tp_stats"
TBLTPRankings = "tp_rankings"
TBLTPTrends = "tp_trends"
@@ -1803,6 +1853,9 @@ const (
CacheResources = "*resources"
CacheResourceProfiles = "*resource_profiles"
CacheEventResources = "*event_resources"
+ CacheIPs = "*ips"
+ CacheIPProfiles = "*ip_profiles"
+ CacheEventIPs = "*event_ips"
CacheStatQueueProfiles = "*statqueue_profiles"
CacheStatQueues = "*statqueues"
CacheRankingProfiles = "*ranking_profiles"
@@ -1819,6 +1872,7 @@ const (
CacheActionProfiles = "*action_profiles"
CacheAccounts = "*accounts"
CacheResourceFilterIndexes = "*resource_filter_indexes"
+ CacheIPFilterIndexes = "*ip_filter_indexes"
CacheStatFilterIndexes = "*stat_filter_indexes"
CacheThresholdFilterIndexes = "*threshold_filter_indexes"
CacheRouteFilterIndexes = "*route_filter_indexes"
@@ -1850,6 +1904,7 @@ const (
// Prefix for indexing
const (
ResourceFilterIndexes = "rfi_"
+ IPFilterIndexes = "ifi_"
StatFilterIndexes = "sfi_"
ThresholdFilterIndexes = "tfi_"
AttributeFilterIndexes = "afi_"
@@ -2535,6 +2590,11 @@ const (
OptsResourcesUsageID = "*rsUsageID"
OptsResourcesUsageTTL = "*rsUsageTTL"
+ // IPs
+ OptsIPsUnits = "*ipUnits"
+ OptsIPsUsageID = "*ipUsageID"
+ OptsIPsTTL = "*ipTTL"
+
// Routes
OptsRoutesProfilesCount = "*rouProfilesCount"
OptsRoutesLimit = "*rouLimit"
diff --git a/utils/ips.go b/utils/ips.go
new file mode 100644
index 000000000..db4ab90ac
--- /dev/null
+++ b/utils/ips.go
@@ -0,0 +1,267 @@
+/*
+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 utils
+
+import (
+ "slices"
+ "time"
+)
+
+// IPProfile defines the configuration of the IP.
+type IPProfile struct {
+ Tenant string
+ ID string
+ FilterIDs []string
+ TTL time.Duration
+ Type string
+ AddressPool string
+ Allocation string
+ Stored bool
+ Weights DynamicWeights
+}
+
+// Clone creates a deep copy of IPProfile for thread-safe use.
+func (ip *IPProfile) Clone() *IPProfile {
+ if ip == nil {
+ return nil
+ }
+ return &IPProfile{
+ Tenant: ip.Tenant,
+ ID: ip.ID,
+ FilterIDs: slices.Clone(ip.FilterIDs),
+ TTL: ip.TTL,
+ Type: ip.Type,
+ AddressPool: ip.AddressPool,
+ Allocation: ip.Allocation,
+ Stored: ip.Stored,
+ Weights: ip.Weights.Clone(),
+ }
+}
+
+// CacheClone returns a clone of IPProfile used by ltcache CacheCloner
+func (ip *IPProfile) CacheClone() any {
+ return ip.Clone()
+}
+
+// IPProfileWithAPIOpts wraps IPProfile with APIOpts.
+type IPProfileWithAPIOpts struct {
+ *IPProfile
+ APIOpts map[string]any
+}
+
+// TenantID returns the concatenated tenant and ID.
+func (ip *IPProfile) TenantID() string {
+ return ConcatenatedKey(ip.Tenant, ip.ID)
+}
+
+// IPUsage represents an usage counted.
+type IPUsage struct {
+ Tenant string
+ ID string
+ ExpiryTime time.Time
+ Units float64
+}
+
+// TenantID returns the concatenated key between tenant and ID.
+func (u *IPUsage) TenantID() string {
+ return ConcatenatedKey(u.Tenant, u.ID)
+}
+
+// isActive checks ExpiryTime at some time
+func (u *IPUsage) IsActive(atTime time.Time) bool {
+ return u.ExpiryTime.IsZero() || u.ExpiryTime.Sub(atTime) > 0
+}
+
+// Clone duplicates ru
+func (u *IPUsage) Clone() *IPUsage {
+ if u == nil {
+ return nil
+ }
+ clone := *u
+ return &clone
+}
+
+// IP represents ...
+type IP struct {
+ Tenant string
+ ID string
+ Usages map[string]*IPUsage
+ TTLIdx []string
+}
+
+// Clone clones *IP (lkID excluded)
+func (ip *IP) Clone() *IP {
+ if ip == nil {
+ return nil
+ }
+ clone := &IP{
+ Tenant: ip.Tenant,
+ ID: ip.ID,
+ TTLIdx: slices.Clone(ip.TTLIdx),
+ }
+ if ip.Usages != nil {
+ clone.Usages = make(map[string]*IPUsage, len(ip.Usages))
+ for key, usage := range ip.Usages {
+ clone.Usages[key] = usage.Clone()
+ }
+ }
+ return clone
+}
+
+// CacheClone returns a clone of IP used by ltcache CacheCloner
+func (ip *IP) CacheClone() any {
+ return ip.Clone()
+}
+
+// IPWithAPIOpts wraps IP with APIOpts.
+type IPWithAPIOpts struct {
+ *IP
+ APIOpts map[string]any
+}
+
+// TenantID returns the unique ID in a multi-tenant environment
+func (ip *IP) TenantID() string {
+ return ConcatenatedKey(ip.Tenant, ip.ID)
+}
+
+// TotalUsage returns the sum of all usage units
+// Exported to be used in FilterS
+func (ip *IP) TotalUsage() float64 {
+ var tu float64
+ for _, ru := range ip.Usages {
+ tu += ru.Units
+ }
+ return tu
+}
+
+func (ip *IPProfile) Set(path []string, val any, _ bool) error {
+ if len(path) != 1 {
+ return ErrWrongPath
+ }
+ var err error
+ switch path[0] {
+ default:
+ return ErrWrongPath
+ case Tenant:
+ ip.Tenant = IfaceAsString(val)
+ case ID:
+ ip.ID = IfaceAsString(val)
+ case FilterIDs:
+ var valA []string
+ valA, err = IfaceAsStringSlice(val)
+ ip.FilterIDs = append(ip.FilterIDs, valA...)
+ case TTL:
+ ip.TTL, err = IfaceAsDuration(val)
+ case Type:
+ ip.Type = IfaceAsString(val)
+ case AddressPool:
+ ip.AddressPool = IfaceAsString(val)
+ case Allocation:
+ ip.Allocation = IfaceAsString(val)
+ case Stored:
+ ip.Stored, err = IfaceAsBool(val)
+ case Weights:
+ if val != "" {
+ ip.Weights, err = NewDynamicWeightsFromString(IfaceAsString(val), InfieldSep, ANDSep)
+ }
+ }
+ return err
+}
+
+func (ip *IPProfile) Merge(v2 any) {
+ vi := v2.(*IPProfile)
+ if len(vi.Tenant) != 0 {
+ ip.Tenant = vi.Tenant
+ }
+ if len(vi.ID) != 0 {
+ ip.ID = vi.ID
+ }
+ ip.FilterIDs = append(ip.FilterIDs, vi.FilterIDs...)
+ if len(vi.Allocation) != 0 {
+ ip.Allocation = vi.Allocation
+ }
+ if vi.TTL != 0 {
+ ip.TTL = vi.TTL
+ }
+ if vi.Type != "" {
+ ip.Type = vi.Type
+ }
+ if vi.AddressPool != "" {
+ ip.AddressPool = vi.AddressPool
+ }
+ if vi.Stored {
+ ip.Stored = vi.Stored
+ }
+ ip.Weights = append(ip.Weights, vi.Weights...)
+}
+
+func (ip *IPProfile) String() string { return ToJSON(ip) }
+func (ip *IPProfile) FieldAsString(fldPath []string) (string, error) {
+ val, err := ip.FieldAsInterface(fldPath)
+ if err != nil {
+ return "", err
+ }
+ return IfaceAsString(val), nil
+}
+func (ip *IPProfile) FieldAsInterface(fldPath []string) (any, error) {
+ if len(fldPath) != 1 {
+ return nil, ErrNotFound
+ }
+ switch fldPath[0] {
+ default:
+ fld, idx := GetPathIndex(fldPath[0])
+ if idx != nil {
+ switch fld {
+ case FilterIDs:
+ if *idx < len(ip.FilterIDs) {
+ return ip.FilterIDs[*idx], nil
+ }
+ }
+ }
+ return nil, ErrNotFound
+ case Tenant:
+ return ip.Tenant, nil
+ case ID:
+ return ip.ID, nil
+ case FilterIDs:
+ return ip.FilterIDs, nil
+ case TTL:
+ return ip.TTL, nil
+ case Type:
+ return ip.Type, nil
+ case AddressPool:
+ return ip.AddressPool, nil
+ case Allocation:
+ return ip.Allocation, nil
+ case Stored:
+ return ip.Stored, nil
+ case Weights:
+ return ip.Weights, nil
+ }
+}
+
+// IPProfileLockKey returns the ID used to lock a resourceProfile with guardian
+func IPProfileLockKey(tnt, id string) string {
+ return ConcatenatedKey(CacheIPProfiles, tnt, id)
+}
+
+// IPLockKey returns the ID used to lock a resource with guardian
+func IPLockKey(tnt, id string) string {
+ return ConcatenatedKey(CacheIPs, tnt, id)
+}