Conflicts:
	engine/loader_csv_test.go
This commit is contained in:
TeoV
2017-09-15 16:27:23 +03:00
12 changed files with 272 additions and 168 deletions

View File

@@ -81,16 +81,17 @@ func (rsv1 *ResourceSV1) ReleaseResource(args utils.AttrRLsResourceUsage, reply
return rsv1.rls.V1ReleaseResource(args, reply)
}
type AttrGetResPrf struct {
ID string
type ArgGetResPrf struct {
Tenant string
ID string
}
// GetResourceProfile returns a resource configuration
func (apierV1 *ApierV1) GetResourceProfile(attr AttrGetResPrf, reply *engine.ResourceProfile) error {
if missing := utils.MissingStructFields(&attr, []string{"ID"}); len(missing) != 0 { //Params missing
func (apierV1 *ApierV1) GetResourceProfile(arg ArgGetResPrf, reply *engine.ResourceProfile) error {
if missing := utils.MissingStructFields(&arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
if rcfg, err := apierV1.DataDB.GetResourceProfile(attr.ID, true, utils.NonTransactional); err != nil {
if rcfg, err := apierV1.DataDB.GetResourceProfile(arg.Tenant, arg.ID, true, utils.NonTransactional); err != nil {
if err.Error() != utils.ErrNotFound.Error() {
err = utils.NewErrServerError(err)
}
@@ -102,11 +103,11 @@ func (apierV1 *ApierV1) GetResourceProfile(attr AttrGetResPrf, reply *engine.Res
}
//SetResourceProfile add a new resource configuration
func (apierV1 *ApierV1) SetResourceProfile(attr *engine.ResourceProfile, reply *string) error {
if missing := utils.MissingStructFields(attr, []string{"ID"}); len(missing) != 0 {
func (apierV1 *ApierV1) SetResourceProfile(res *engine.ResourceProfile, reply *string) error {
if missing := utils.MissingStructFields(res, []string{"Tenant", "ID"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if err := apierV1.DataDB.SetResourceProfile(attr, utils.NonTransactional); err != nil {
if err := apierV1.DataDB.SetResourceProfile(res, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
@@ -114,11 +115,11 @@ func (apierV1 *ApierV1) SetResourceProfile(attr *engine.ResourceProfile, reply *
}
//RemResourceProfile remove a specific resource configuration
func (apierV1 *ApierV1) RemResourceProfile(attrs AttrGetResPrf, reply *string) error {
if missing := utils.MissingStructFields(&attrs, []string{"ID"}); len(missing) != 0 { //Params missing
func (apierV1 *ApierV1) RemResourceProfile(arg ArgGetResPrf, reply *string) error {
if missing := utils.MissingStructFields(&arg, []string{"Tenant", "ID"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
if err := apierV1.DataDB.RemoveResourceProfile(attrs.ID, utils.NonTransactional); err != nil {
if err := apierV1.DataDB.RemoveResourceProfile(arg.Tenant, arg.ID, utils.NonTransactional); err != nil {
if err.Error() != utils.ErrNotFound.Error() {
err = utils.NewErrServerError(err)
}

View File

@@ -1,8 +1,8 @@
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],TTL[6],Limit[7],AllocationMessage[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
Tester,ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,1s,7,,true,true,20,
Tester,ResGroup1,*string_prefix,Destination,10;20,,,,,,,,
Tester,ResGroup1,*rsr_fields,,Subject(~^1.*1$);Destination(1002),,,,,,,,
Tester,ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,3600s,8,SPECIAL_1002,true,true,10,
Tester,ResGroup3,*string,Account,3001,2014-07-29T15:00:00Z,1s,3,,true,true,20,
#ResGroup3,*timings,SetupTime,PEAK,,,,,,,,
#ResGroup3,*cdr_stats,,CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20,,,,,,,,
cgrates.org,ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,1s,7,,true,true,20,
cgrates.org,ResGroup1,*string_prefix,Destination,10;20,,,,,,,,
cgrates.org,ResGroup1,*rsr_fields,,Subject(~^1.*1$);Destination(1002),,,,,,,,
cgrates.org,ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,3600s,8,SPECIAL_1002,true,true,10,
cgrates.org,ResGroup3,*string,Account,3001,2014-07-29T15:00:00Z,1s,3,,true,true,20,
#cgrates.org,ResGroup3,*timings,SetupTime,PEAK,,,,,,,,
#cgrates.org,ResGroup3,*cdr_stats,,CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20,,,,,,,,
1 #Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],TTL[6],Limit[7],AllocationMessage[8],Blocker[9],Stored[10],Weight[11],Thresholds[12] #Tenant[0] Id[1] FilterType[2] FilterFieldName[3] FilterFieldValues[4] ActivationInterval[5] TTL[6] Limit[7] AllocationMessage[8] Blocker[9] Stored[10] Weight[11] Thresholds[12]
2 Tester,ResGroup1,*string,Account,1001;1002,2014-07-29T15:00:00Z,1s,7,,true,true,20, cgrates.org ResGroup1 *string Account 1001;1002 2014-07-29T15:00:00Z 1s 7 true true 20
3 Tester,ResGroup1,*string_prefix,Destination,10;20,,,,,,,, cgrates.org ResGroup1 *string_prefix Destination 10;20
4 Tester,ResGroup1,*rsr_fields,,Subject(~^1.*1$);Destination(1002),,,,,,,, cgrates.org ResGroup1 *rsr_fields Subject(~^1.*1$);Destination(1002)
5 Tester,ResGroup2,*destinations,Destination,DST_FS,2014-07-29T15:00:00Z,3600s,8,SPECIAL_1002,true,true,10, cgrates.org ResGroup2 *destinations Destination DST_FS 2014-07-29T15:00:00Z 3600s 8 SPECIAL_1002 true true 10
6 Tester,ResGroup3,*string,Account,3001,2014-07-29T15:00:00Z,1s,3,,true,true,20, cgrates.org ResGroup3 *string Account 3001 2014-07-29T15:00:00Z 1s 3 true true 20
7 #ResGroup3,*timings,SetupTime,PEAK,,,,,,,, #cgrates.org ResGroup3 *timings SetupTime PEAK
8 #ResGroup3,*cdr_stats,,CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20,,,,,,,, #cgrates.org ResGroup3 *cdr_stats CDRST1:*min_ASR:34;CDRST_1001:*min_ASR:20

View File

@@ -266,11 +266,19 @@ cgrates.org,mas,true,another,value,10
*out,cgrates.org,call,remo,remo,*any,*rating,Account,remo,minu,10
`
resProfiles = `
<<<<<<< HEAD
#Id[0]Tenant[1],,FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],TTL[6],Limit[7],AllocationMessage[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
ResGroup21,cgrates.org,*string,HdrAccount,1001;1002,2014-07-29T15:00:00Z,1s,2,call,true,true,10,
ResGroup21,cgrates.org,*string_prefix,HdrDestination,10;20,,,,,,,,
ResGroup21,cgrates.org,*rsr_fields,,HdrSubject(~^1.*1$);HdrDestination(1002),,,,,,,,
ResGroup22,cgrates.org,*destinations,HdrDestination,DST_FS,2014-07-29T15:00:00Z,3600s,2,premium_call,true,true,10,
=======
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],TTL[6],Limit[7],AllocationMessage[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
cgrates.org,ResGroup21,*string,HdrAccount,1001;1002,2014-07-29T15:00:00Z,1s,2,call,true,true,10,
cgrates.org,ResGroup21,*string_prefix,HdrDestination,10;20,,,,,,,,
cgrates.org,ResGroup21,*rsr_fields,,HdrSubject(~^1.*1$);HdrDestination(1002),,,,,,,,
cgrates.org,ResGroup22,*destinations,HdrDestination,DST_FS,2014-07-29T15:00:00Z,3600s,2,premium_call,true,true,10,
>>>>>>> 72be574e2485078deacebbbd01c7df1d05991615
`
stats = `
#Tenant[0],Id[1],FilterType[2],FilterFieldName[3],FilterFieldValues[4],ActivationInterval[5],QueueLength[6],TTL[7],Metrics[8],Blocker[9],Stored[10],Weight[11],Thresholds[12]
@@ -1390,6 +1398,7 @@ func TestLoadReverseAliases(t *testing.T) {
}
func TestLoadResourceProfiles(t *testing.T) {
<<<<<<< HEAD
eResProfiles := map[string]*utils.TPResource{
"ResGroup21": &utils.TPResource{
TPid: testTPID,
@@ -1414,20 +1423,48 @@ func TestLoadResourceProfiles(t *testing.T) {
ID: "ResGroup22",
Filters: []*utils.TPRequestFilter{
&utils.TPRequestFilter{Type: MetaDestinations, FieldName: "HdrDestination", Values: []string{"DST_FS"}},
=======
eResProfiles := map[string]map[string]*utils.TPResource{
"cgrates.org": map[string]*utils.TPResource{
"ResGroup21": &utils.TPResource{
TPid: testTPID,
Tenant: "cgrates.org",
ID: "ResGroup21",
Filters: []*utils.TPRequestFilter{
&utils.TPRequestFilter{Type: MetaString, FieldName: "HdrAccount", Values: []string{"1001", "1002"}},
&utils.TPRequestFilter{Type: MetaStringPrefix, FieldName: "HdrDestination", Values: []string{"10", "20"}},
&utils.TPRequestFilter{Type: MetaRSRFields, Values: []string{"HdrSubject(~^1.*1$)", "HdrDestination(1002)"}},
},
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-29T15:00:00Z",
},
UsageTTL: "1s",
AllocationMessage: "call",
Weight: 10,
Limit: "2",
>>>>>>> 72be574e2485078deacebbbd01c7df1d05991615
},
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-29T15:00:00Z",
"ResGroup22": &utils.TPResource{
TPid: testTPID,
Tenant: "cgrates.org",
ID: "ResGroup22",
Filters: []*utils.TPRequestFilter{
&utils.TPRequestFilter{Type: MetaDestinations, FieldName: "HdrDestination", Values: []string{"DST_FS"}},
},
ActivationInterval: &utils.TPActivationInterval{
ActivationTime: "2014-07-29T15:00:00Z",
},
UsageTTL: "3600s",
AllocationMessage: "premium_call",
Blocker: true,
Stored: true,
Weight: 10,
Limit: "2",
},
UsageTTL: "3600s",
AllocationMessage: "premium_call",
Blocker: true,
Stored: true,
Weight: 10,
Limit: "2",
},
}
if len(csvr.resProfiles) != len(eResProfiles) {
t.Error("Failed to load resourceProfiles: ", len(csvr.resProfiles))
if len(csvr.resProfiles["cgrates.org"]) != len(eResProfiles["cgrates.org"]) {
t.Errorf("Failed to load resourceProfiles: %s", utils.ToIJSON(csvr.resProfiles))
} else if !reflect.DeepEqual(eResProfiles["ResGroup22"], csvr.resProfiles["ResGroup22"]) {
t.Errorf("Expecting: %+v, received: %+v", eResProfiles["ResGroup22"], csvr.resProfiles["ResGroup22"])

View File

@@ -309,17 +309,19 @@ func TestLoaderITWriteToDatabase(t *testing.T) {
}
}
for k, rl := range loader.resProfiles {
rcv, err := loader.dataStorage.GetResourceProfile(k, true, utils.NonTransactional)
if err != nil {
t.Error("Failed GetResourceProfile: ", err.Error())
}
rlT, err := APItoResource(rl, "UTC")
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(rlT, rcv) {
t.Errorf("Expecting: %v, received: %v", rlT, rcv)
for _, mapIDs := range loader.resProfiles {
for _, rl := range mapIDs {
rcv, err := loader.dataStorage.GetResourceProfile(rl.Tenant, rl.ID, true, utils.NonTransactional)
if err != nil {
t.Error("Failed GetResourceProfile: ", err.Error())
}
rlT, err := APItoResource(rl, "UTC")
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(rlT, rcv) {
t.Errorf("Expecting: %v, received: %v", rlT, rcv)
}
}
}

View File

@@ -782,6 +782,7 @@ func testOnStorITCacheReverseAlias(t *testing.T) {
func testOnStorITCacheResourceProfile(t *testing.T) {
rCfg := &ResourceProfile{
Tenant: "cgrates.org",
ID: "RL_TEST",
Weight: 10,
Filters: []*RequestFilter{
@@ -799,19 +800,19 @@ func testOnStorITCacheResourceProfile(t *testing.T) {
if err := onStor.SetResourceProfile(rCfg, utils.NonTransactional); err != nil {
t.Error(err)
}
expectedR := []string{"rsp_RL_TEST"}
expectedR := []string{"rsp_cgrates.org:RL_TEST"}
if itm, err := onStor.GetKeysForPrefix(utils.ResourceProfilesPrefix); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expectedR, itm) {
t.Errorf("Expected : %+v, but received %+v", expectedR, itm)
}
if _, hasIt := cache.Get(utils.ResourceProfilesPrefix + rCfg.ID); hasIt {
if _, hasIt := cache.Get(utils.ResourceProfilesPrefix + rCfg.TenantID()); hasIt {
t.Error("Already in cache")
}
if err := onStor.CacheDataFromDB(utils.ResourceProfilesPrefix, []string{rCfg.ID}, false); err != nil {
if err := onStor.CacheDataFromDB(utils.ResourceProfilesPrefix, []string{rCfg.TenantID()}, false); err != nil {
t.Error(err)
}
if itm, hasIt := cache.Get(utils.ResourceProfilesPrefix + rCfg.ID); !hasIt {
if itm, hasIt := cache.Get(utils.ResourceProfilesPrefix + rCfg.TenantID()); !hasIt {
t.Error("Did not cache")
} else if rcv := itm.(*ResourceProfile); !reflect.DeepEqual(rCfg, rcv) {
t.Errorf("Expecting: %+v, received: %+v", rCfg, rcv)
@@ -853,7 +854,8 @@ func testOnStorITCacheTiming(t *testing.T) {
func testOnStorITCacheResource(t *testing.T) {
res := &Resource{
ID: "RL1",
Tenant: "cgrates.org",
ID: "RL1",
Usages: map[string]*ResourceUsage{
"RU1": &ResourceUsage{
ID: "RU1",
@@ -866,20 +868,20 @@ func testOnStorITCacheResource(t *testing.T) {
if err := onStor.SetResource(res); err != nil {
t.Error(err)
}
expectedT := []string{"res_RL1"}
expectedT := []string{"res_cgrates.org:RL1"}
if itm, err := onStor.GetKeysForPrefix(utils.ResourcesPrefix); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(expectedT, itm) {
t.Errorf("Expected : %+v, but received %+v", expectedT, itm)
}
if _, hasIt := cache.Get(utils.ResourcesPrefix + res.ID); hasIt {
if _, hasIt := cache.Get(utils.ResourcesPrefix + res.TenantID()); hasIt {
t.Error("Already in cache")
}
if err := onStor.CacheDataFromDB(utils.ResourcesPrefix, []string{res.ID}, false); err != nil {
if err := onStor.CacheDataFromDB(utils.ResourcesPrefix, []string{res.TenantID()}, false); err != nil {
t.Error(err)
}
if itm, hasIt := cache.Get(utils.ResourcesPrefix + res.ID); !hasIt {
if itm, hasIt := cache.Get(utils.ResourcesPrefix + res.TenantID()); !hasIt {
t.Error("Did not cache")
} else if rcv := itm.(*Resource); !reflect.DeepEqual(res, rcv) {
t.Errorf("Expecting: %+v, received: %+v", res, rcv)
@@ -1798,13 +1800,13 @@ func testOnStorITCRUDResourceProfile(t *testing.T) {
Thresholds: []string{"TEST_ACTIONS"},
UsageTTL: time.Duration(1 * time.Millisecond),
}
if _, rcvErr := onStor.GetResourceProfile(rL.ID, true, utils.NonTransactional); rcvErr != utils.ErrNotFound {
if _, rcvErr := onStor.GetResourceProfile(rL.Tenant, rL.ID, true, utils.NonTransactional); rcvErr != utils.ErrNotFound {
t.Error(rcvErr)
}
if err := onStor.SetResourceProfile(rL, utils.NonTransactional); err != nil {
t.Error(err)
}
if rcv, err := onStor.GetResourceProfile(rL.ID, true, utils.NonTransactional); err != nil {
if rcv, err := onStor.GetResourceProfile(rL.Tenant, rL.ID, true, utils.NonTransactional); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rL, rcv) {
t.Errorf("Expecting: %v, received: %v", rL, rcv)
@@ -1817,7 +1819,7 @@ func testOnStorITCRUDResourceProfile(t *testing.T) {
// t.Error(rcvErr)
// }
//
if rcv, err := onStor.GetResourceProfile(rL.ID, false, utils.NonTransactional); err != nil {
if rcv, err := onStor.GetResourceProfile(rL.Tenant, rL.ID, false, utils.NonTransactional); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(rL, rcv) {
t.Errorf("Expecting: %v, received: %v", rL, rcv)
@@ -1825,17 +1827,18 @@ func testOnStorITCRUDResourceProfile(t *testing.T) {
// if err = onStor.SelectDatabase(onStorCfg); err != nil {
// t.Error(err)
// }
if err := onStor.RemoveResourceProfile(rL.ID, utils.NonTransactional); err != nil {
if err := onStor.RemoveResourceProfile(rL.Tenant, rL.ID, utils.NonTransactional); err != nil {
t.Error(err)
}
if _, rcvErr := onStor.GetResourceProfile(rL.ID, true, utils.NonTransactional); rcvErr != utils.ErrNotFound {
if _, rcvErr := onStor.GetResourceProfile(rL.Tenant, rL.ID, true, utils.NonTransactional); rcvErr != utils.ErrNotFound {
t.Error(rcvErr)
}
}
func testOnStorITCRUDResource(t *testing.T) {
res := &Resource{
ID: "RL1",
Tenant: "cgrates.org",
ID: "RL1",
Usages: map[string]*ResourceUsage{
"RU1": &ResourceUsage{
ID: "RU1",
@@ -1845,26 +1848,26 @@ func testOnStorITCRUDResource(t *testing.T) {
},
TTLIdx: []string{"RU1"},
}
if _, rcvErr := onStor.GetResource("RL1", true, utils.NonTransactional); rcvErr != nil && rcvErr != utils.ErrNotFound {
if _, rcvErr := onStor.GetResource("cgrates.org", "RL1", true, utils.NonTransactional); rcvErr != nil && rcvErr != utils.ErrNotFound {
t.Error(rcvErr)
}
if err := onStor.SetResource(res); err != nil {
t.Error(err)
}
if rcv, err := onStor.GetResource("RL1", true, utils.NonTransactional); err != nil {
if rcv, err := onStor.GetResource("cgrates.org", "RL1", true, utils.NonTransactional); err != nil {
t.Error(err)
} else if !(reflect.DeepEqual(res, rcv)) {
t.Errorf("Expecting: %v, received: %v", res, rcv)
}
if rcv, err := onStor.GetResource("RL1", false, utils.NonTransactional); err != nil {
if rcv, err := onStor.GetResource("cgrates.org", "RL1", false, utils.NonTransactional); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(res, rcv) {
t.Errorf("Expecting: %v, received: %v", res, rcv)
}
if err := onStor.RemoveResource(res.ID, utils.NonTransactional); err != nil {
if err := onStor.RemoveResource(res.Tenant, res.ID, utils.NonTransactional); err != nil {
t.Error(err)
}
if _, rcvErr := onStor.GetResource(res.ID, true, utils.NonTransactional); rcvErr != utils.ErrNotFound {
if _, rcvErr := onStor.GetResource(res.Tenant, res.ID, true, utils.NonTransactional); rcvErr != utils.ErrNotFound {
t.Error(rcvErr)
}
}

View File

@@ -52,6 +52,11 @@ type ResourceProfile struct {
Thresholds []string // Thresholds to check after changing Limit
}
// TenantID returns unique identifier of the ResourceProfile in a multi-tenant environment
func (rp *ResourceProfile) TenantID() string {
return utils.ConcatenatedKey(rp.Tenant, rp.ID)
}
// ResourceUsage represents an usage counted
type ResourceUsage struct {
Tenant string
@@ -77,6 +82,11 @@ type Resource struct {
rPrf *ResourceProfile // for ordering purposes
}
// TenantID returns the unique ID in a multi-tenant environment
func (r *Resource) TenantID() string {
return utils.ConcatenatedKey(r.Tenant, r.ID)
}
// removeExpiredUnits removes units which are expired from the resource
func (r *Resource) removeExpiredUnits() {
var firstActive int
@@ -182,13 +192,21 @@ func (rs Resources) clearUsage(ruID string) (err error) {
return
}
// ids returns list of resource IDs in resources
func (rs Resources) ids() (ids []string) {
ids = make([]string, len(rs))
// tenantIDs returns list of TenantIDs in resources
func (rs Resources) tenantIDs() []*utils.TenantID {
tntIDs := make([]*utils.TenantID, len(rs))
for i, r := range rs {
ids[i] = r.ID
tntIDs[i] = &utils.TenantID{r.Tenant, r.ID}
}
return
return tntIDs
}
func (rs Resources) tenatIDsStr() []string {
ids := make([]string, len(rs))
for i, r := range rs {
ids[i] = r.TenantID()
}
return ids
}
// AllocateResource attempts allocating resources for a *ResourceUsage
@@ -198,7 +216,7 @@ func (rs Resources) AllocateResource(ru *ResourceUsage, dryRun bool) (alcMessage
if len(rs) == 0 {
return "", utils.ErrResourceUnavailable
}
lockIDs := utils.PrefixSliceItems(rs.ids(), utils.ResourcesPrefix)
lockIDs := utils.PrefixSliceItems(rs.tenatIDsStr(), utils.ResourcesPrefix)
guardian.Guardian.GuardIDs(config.CgrConfig().LockingTimeout, lockIDs...)
defer guardian.Guardian.UnguardIDs(lockIDs...)
// Simulate resource usage
@@ -229,7 +247,7 @@ func NewResourceService(dataDB DataDB, storeInterval time.Duration,
statS = nil
}
return &ResourceService{dataDB: dataDB, statS: statS,
lcEventResources: make(map[string][]string),
lcEventResources: make(map[string][]*utils.TenantID),
storedResources: make(utils.StringMap),
storeInterval: storeInterval, stopBackup: make(chan struct{})}, nil
}
@@ -238,7 +256,7 @@ func NewResourceService(dataDB DataDB, storeInterval time.Duration,
type ResourceService struct {
dataDB DataDB // So we can load the data in cache and index it
statS rpcclient.RpcClientConnection // allows applying filters based on stats
lcEventResources map[string][]string // cache recording resources for events in alocation phase
lcEventResources map[string][]*utils.TenantID // cache recording resources for events in alocation phase
lcERMux sync.RWMutex // protects the lcEventResources
storedResources utils.StringMap // keep a record of resources which need saving, map[resID]bool
srMux sync.RWMutex // protects storedResources
@@ -335,7 +353,7 @@ func (rS *ResourceService) cachedResourcesForEvent(evUUID string) (rs Resources)
if rIDsIf, has := cache.Get(utils.EventResourcesPrefix + evUUID); !has {
return nil
} else if rIDsIf != nil {
rIDs = rIDsIf.([]string)
rIDs = rIDsIf.([]*utils.TenantID)
}
shortCached = true
}
@@ -343,11 +361,14 @@ func (rS *ResourceService) cachedResourcesForEvent(evUUID string) (rs Resources)
if len(rIDs) == 0 {
return
}
lockIDs := utils.PrefixSliceItems(rIDs, utils.ResourcesPrefix)
lockIDs := make([]string, len(rIDs))
for i, rTid := range rIDs {
lockIDs[i] = utils.ResourcesPrefix + rTid.TenantID()
}
guardian.Guardian.GuardIDs(config.CgrConfig().LockingTimeout, lockIDs...)
defer guardian.Guardian.UnguardIDs(lockIDs...)
for i, rID := range rIDs {
if r, err := rS.dataDB.GetResource(rID, false, ""); err != nil {
for i, rTid := range rIDs {
if r, err := rS.dataDB.GetResource(rTid.Tenant, rTid.ID, false, ""); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<ResourceS> force-uncaching resources for evUUID: <%s>, error: <%s>",
evUUID, err.Error()))
@@ -378,7 +399,8 @@ func (rS *ResourceService) matchingResourcesForEvent(ev map[string]interface{})
guardian.Guardian.GuardIDs(config.CgrConfig().LockingTimeout, lockIDs...)
defer guardian.Guardian.UnguardIDs(lockIDs...)
for resName := range rIDs {
rPrf, err := rS.dataDB.GetResourceProfile(resName, false, utils.NonTransactional)
rTntID := utils.NewTenantID(resName)
rPrf, err := rS.dataDB.GetResourceProfile(rTntID.Tenant, rTntID.ID, false, utils.NonTransactional)
if err != nil {
if err == utils.ErrNotFound {
continue
@@ -401,7 +423,7 @@ func (rS *ResourceService) matchingResourcesForEvent(ev map[string]interface{})
if !passAllFilters {
continue
}
r, err := rS.dataDB.GetResource(rPrf.ID, false, "")
r, err := rS.dataDB.GetResource(rPrf.Tenant, rPrf.ID, false, "")
if err != nil {
return nil, err
}
@@ -450,7 +472,7 @@ func (rS *ResourceService) V1AllowUsage(args utils.AttrRLsResourceUsage, allow *
if mtcRLs, err = rS.matchingResourcesForEvent(args.Event); err != nil {
return err
}
cache.Set(utils.EventResourcesPrefix+args.UsageID, mtcRLs.ids(), true, "")
cache.Set(utils.EventResourcesPrefix+args.UsageID, mtcRLs.tenantIDs(), true, "")
}
if _, err = mtcRLs.AllocateResource(
&ResourceUsage{ID: args.UsageID,
@@ -493,7 +515,7 @@ func (rS *ResourceService) V1AllocateResource(args utils.AttrRLsResourceUsage, r
}
if wasShortCached || !wasCached {
rS.lcERMux.Lock()
rS.lcEventResources[args.UsageID] = mtcRLs.ids()
rS.lcEventResources[args.UsageID] = mtcRLs.tenantIDs()
rS.lcERMux.Unlock()
}
// index it for storing

View File

@@ -99,12 +99,12 @@ type DataDB interface {
RemoveAlias(string, string) error
SetReverseAlias(*Alias, string) error
GetReverseAlias(string, bool, string) ([]string, error)
GetResourceProfile(string, bool, string) (*ResourceProfile, error)
GetResourceProfile(string, string, bool, string) (*ResourceProfile, error)
SetResourceProfile(*ResourceProfile, string) error
RemoveResourceProfile(string, string) error
GetResource(string, bool, string) (*Resource, error)
RemoveResourceProfile(string, string, string) error
GetResource(string, string, bool, string) (*Resource, error)
SetResource(*Resource) error
RemoveResource(string, string) error
RemoveResource(string, string, string) error
GetTiming(string, bool, string) (*utils.TPTiming, error)
SetTiming(*utils.TPTiming, string) error
RemoveTiming(string, string) error

View File

@@ -193,6 +193,7 @@ func (ms *MapStorage) PreloadCacheForPrefix(prefix string) error {
// CacheDataFromDB loads data to cache,
// prefix represents the cache prefix, IDs should be nil if all available data should be loaded
// ToDo: convert IDs into []*utils.TenantIDs when infrastructure will be ready
func (ms *MapStorage) CacheDataFromDB(prefix string, IDs []string, mustBeCached bool) (err error) {
if !utils.IsSliceMember([]string{utils.DESTINATION_PREFIX,
utils.REVERSE_DESTINATION_PREFIX,
@@ -273,9 +274,11 @@ func (ms *MapStorage) CacheDataFromDB(prefix string, IDs []string, mustBeCached
case utils.REVERSE_ALIASES_PREFIX:
_, err = ms.GetReverseAlias(dataID, true, utils.NonTransactional)
case utils.ResourceProfilesPrefix:
_, err = ms.GetResourceProfile(dataID, true, utils.NonTransactional)
tntID := utils.NewTenantID(dataID)
_, err = ms.GetResourceProfile(tntID.Tenant, tntID.ID, true, utils.NonTransactional)
case utils.ResourcesPrefix:
_, err = ms.GetResource(dataID, true, utils.NonTransactional)
tntID := utils.NewTenantID(dataID)
_, err = ms.GetResource(tntID.Tenant, tntID.ID, true, utils.NonTransactional)
case utils.TimingsPrefix:
_, err = ms.GetTiming(dataID, true, utils.NonTransactional)
}
@@ -1276,10 +1279,10 @@ func (ms *MapStorage) GetSMCost(cgrid, source, runid, originHost, originID strin
return
}
func (ms *MapStorage) GetResourceProfile(id string, skipCache bool, transactionID string) (rsp *ResourceProfile, err error) {
func (ms *MapStorage) GetResourceProfile(tenant, id string, skipCache bool, transactionID string) (rsp *ResourceProfile, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
key := utils.ResourceProfilesPrefix + id
key := utils.ResourceProfilesPrefix + utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x != nil {
@@ -1313,23 +1316,23 @@ func (ms *MapStorage) SetResourceProfile(r *ResourceProfile, transactionID strin
if err != nil {
return err
}
ms.dict[utils.ResourceProfilesPrefix+r.ID] = result
ms.dict[utils.ResourceProfilesPrefix+r.TenantID()] = result
return nil
}
func (ms *MapStorage) RemoveResourceProfile(id string, transactionID string) error {
func (ms *MapStorage) RemoveResourceProfile(tenant, id string, transactionID string) error {
ms.mu.Lock()
defer ms.mu.Unlock()
key := utils.ResourceProfilesPrefix + id
key := utils.ResourceProfilesPrefix + utils.ConcatenatedKey(tenant, id)
delete(ms.dict, key)
cache.RemKey(key, cacheCommit(transactionID), transactionID)
return nil
}
func (ms *MapStorage) GetResource(id string, skipCache bool, transactionID string) (r *Resource, err error) {
func (ms *MapStorage) GetResource(tenant, id string, skipCache bool, transactionID string) (r *Resource, err error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
key := utils.ResourcesPrefix + id
key := utils.ResourcesPrefix + utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x != nil {
@@ -1358,14 +1361,14 @@ func (ms *MapStorage) SetResource(r *Resource) (err error) {
if err != nil {
return err
}
ms.dict[utils.ResourcesPrefix+r.ID] = result
ms.dict[utils.ResourcesPrefix+r.TenantID()] = result
return
}
func (ms *MapStorage) RemoveResource(id string, transactionID string) (err error) {
func (ms *MapStorage) RemoveResource(tenant, id string, transactionID string) (err error) {
ms.mu.Lock()
defer ms.mu.Unlock()
key := utils.ResourcesPrefix + id
key := utils.ResourcesPrefix + utils.ConcatenatedKey(tenant, id)
delete(ms.dict, key)
cache.RemKey(key, cacheCommit(transactionID), transactionID)
return

View File

@@ -526,9 +526,11 @@ func (ms *MongoStorage) CacheDataFromDB(prfx string, ids []string, mustBeCached
case utils.REVERSE_ALIASES_PREFIX:
_, err = ms.GetReverseAlias(dataID, true, utils.NonTransactional)
case utils.ResourceProfilesPrefix:
_, err = ms.GetResourceProfile(dataID, true, utils.NonTransactional)
tntID := utils.NewTenantID(dataID)
_, err = ms.GetResourceProfile(tntID.Tenant, tntID.ID, true, utils.NonTransactional)
case utils.ResourcesPrefix:
_, err = ms.GetResource(dataID, true, utils.NonTransactional)
tntID := utils.NewTenantID(dataID)
_, err = ms.GetResource(tntID.Tenant, tntID.ID, true, utils.NonTransactional)
case utils.TimingsPrefix:
_, err = ms.GetTiming(dataID, true, utils.NonTransactional)
}
@@ -554,7 +556,7 @@ func (ms *MongoStorage) GetKeysForPrefix(prefix string) (result []string, err er
defer session.Close()
db := session.DB(ms.db)
keyResult := struct{ Key string }{}
idResult := struct{ Id string }{}
idResult := struct{ Tenant, Id string }{}
switch category {
case utils.DESTINATION_PREFIX:
iter := db.C(colDst).Find(bson.M{"key": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"key": 1}).Iter()
@@ -622,14 +624,14 @@ func (ms *MongoStorage) GetKeysForPrefix(prefix string) (result []string, err er
result = append(result, utils.REVERSE_ALIASES_PREFIX+keyResult.Key)
}
case utils.ResourceProfilesPrefix:
iter := db.C(colRsP).Find(bson.M{"id": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"id": 1}).Iter()
iter := db.C(colRsP).Find(bson.M{"id": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"tenant": 1, "id": 1}).Iter()
for iter.Next(&idResult) {
result = append(result, utils.ResourceProfilesPrefix+idResult.Id)
result = append(result, utils.ResourceProfilesPrefix+utils.ConcatenatedKey(idResult.Tenant, idResult.Id))
}
case utils.ResourcesPrefix:
iter := db.C(colRes).Find(bson.M{"id": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"id": 1}).Iter()
iter := db.C(colRes).Find(bson.M{"id": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"tenant": 1, "id": 1}).Iter()
for iter.Next(&idResult) {
result = append(result, utils.ResourcesPrefix+idResult.Id)
result = append(result, utils.ResourcesPrefix+utils.ConcatenatedKey(idResult.Tenant, idResult.Id))
}
case utils.StatQueuePrefix:
iter := db.C(colStq).Find(bson.M{"id": bson.M{"$regex": bson.RegEx{Pattern: subject}}}).Select(bson.M{"id": 1}).Iter()
@@ -1830,8 +1832,8 @@ func (ms *MongoStorage) GetAllCdrStats() (css []*CdrStats, err error) {
return
}
func (ms *MongoStorage) GetResourceProfile(id string, skipCache bool, transactionID string) (rp *ResourceProfile, err error) {
key := utils.ResourceProfilesPrefix + id
func (ms *MongoStorage) GetResourceProfile(tenant, id string, skipCache bool, transactionID string) (rp *ResourceProfile, err error) {
key := utils.ResourceProfilesPrefix + utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x == nil {
@@ -1843,7 +1845,7 @@ func (ms *MongoStorage) GetResourceProfile(id string, skipCache bool, transactio
session, col := ms.conn(colRsP)
defer session.Close()
rp = new(ResourceProfile)
if err = col.Find(bson.M{"id": id}).One(rp); err != nil {
if err = col.Find(bson.M{"tenant": tenant, "id": id}).One(rp); err != nil {
if err == mgo.ErrNotFound {
err = utils.ErrNotFound
cache.Set(key, nil, cacheCommit(transactionID), transactionID)
@@ -1862,22 +1864,23 @@ func (ms *MongoStorage) GetResourceProfile(id string, skipCache bool, transactio
func (ms *MongoStorage) SetResourceProfile(rp *ResourceProfile, transactionID string) (err error) {
session, col := ms.conn(colRsP)
defer session.Close()
_, err = col.Upsert(bson.M{"id": rp.ID}, rp)
_, err = col.Upsert(bson.M{"tenant": rp.Tenant, "id": rp.ID}, rp)
return
}
func (ms *MongoStorage) RemoveResourceProfile(id string, transactionID string) (err error) {
func (ms *MongoStorage) RemoveResourceProfile(tenant, id string, transactionID string) (err error) {
session, col := ms.conn(colRsP)
defer session.Close()
if err = col.Remove(bson.M{"id": id}); err != nil {
if err = col.Remove(bson.M{"tenant": tenant, "id": id}); err != nil {
return
}
cache.RemKey(utils.ResourceProfilesPrefix+id, cacheCommit(transactionID), transactionID)
cache.RemKey(utils.ResourceProfilesPrefix+utils.ConcatenatedKey(tenant, id),
cacheCommit(transactionID), transactionID)
return nil
}
func (ms *MongoStorage) GetResource(id string, skipCache bool, transactionID string) (r *Resource, err error) {
key := utils.ResourcesPrefix + id
func (ms *MongoStorage) GetResource(tenant, id string, skipCache bool, transactionID string) (r *Resource, err error) {
key := utils.ResourcesPrefix + utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x == nil {
@@ -1889,7 +1892,7 @@ func (ms *MongoStorage) GetResource(id string, skipCache bool, transactionID str
session, col := ms.conn(colRes)
defer session.Close()
r = new(Resource)
if err = col.Find(bson.M{"id": id}).One(r); err != nil {
if err = col.Find(bson.M{"tenant": tenant, "id": id}).One(r); err != nil {
if err == mgo.ErrNotFound {
err = utils.ErrNotFound
cache.Set(key, nil, cacheCommit(transactionID), transactionID)
@@ -1903,17 +1906,18 @@ func (ms *MongoStorage) GetResource(id string, skipCache bool, transactionID str
func (ms *MongoStorage) SetResource(r *Resource) (err error) {
session, col := ms.conn(colRes)
defer session.Close()
_, err = col.Upsert(bson.M{"id": r.ID}, r)
_, err = col.Upsert(bson.M{"tenant": r.Tenant, "id": r.ID}, r)
return
}
func (ms *MongoStorage) RemoveResource(id string, transactionID string) (err error) {
func (ms *MongoStorage) RemoveResource(tenant, id string, transactionID string) (err error) {
session, col := ms.conn(colRes)
defer session.Close()
if err = col.Remove(bson.M{"id": id}); err != nil {
if err = col.Remove(bson.M{"tenant": tenant, "id": id}); err != nil {
return
}
cache.RemKey(utils.ResourcesPrefix+id, cacheCommit(transactionID), transactionID)
cache.RemKey(utils.ResourcesPrefix+utils.ConcatenatedKey(tenant, id),
cacheCommit(transactionID), transactionID)
return nil
}

View File

@@ -288,9 +288,11 @@ func (rs *RedisStorage) CacheDataFromDB(prfx string, ids []string, mustBeCached
case utils.REVERSE_ALIASES_PREFIX:
_, err = rs.GetReverseAlias(dataID, true, utils.NonTransactional)
case utils.ResourceProfilesPrefix:
_, err = rs.GetResourceProfile(dataID, true, utils.NonTransactional)
tntID := utils.NewTenantID(dataID)
_, err = rs.GetResourceProfile(tntID.Tenant, tntID.ID, true, utils.NonTransactional)
case utils.ResourcesPrefix:
_, err = rs.GetResource(dataID, true, utils.NonTransactional)
tntID := utils.NewTenantID(dataID)
_, err = rs.GetResource(tntID.Tenant, tntID.ID, true, utils.NonTransactional)
case utils.TimingsPrefix:
_, err = rs.GetTiming(dataID, true, utils.NonTransactional)
}
@@ -1350,8 +1352,8 @@ func (rs *RedisStorage) GetAllCdrStats() (css []*CdrStats, err error) {
return
}
func (rs *RedisStorage) GetResourceProfile(id string, skipCache bool, transactionID string) (rsp *ResourceProfile, err error) {
key := utils.ResourceProfilesPrefix + id
func (rs *RedisStorage) GetResourceProfile(tenant, id string, skipCache bool, transactionID string) (rsp *ResourceProfile, err error) {
key := utils.ResourceProfilesPrefix + utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x == nil {
@@ -1385,11 +1387,11 @@ func (rs *RedisStorage) SetResourceProfile(rsp *ResourceProfile, transactionID s
if err != nil {
return err
}
return rs.Cmd("SET", utils.ResourceProfilesPrefix+rsp.ID, result).Err
return rs.Cmd("SET", utils.ResourceProfilesPrefix+rsp.TenantID(), result).Err
}
func (rs *RedisStorage) RemoveResourceProfile(id string, transactionID string) (err error) {
key := utils.ResourceProfilesPrefix + id
func (rs *RedisStorage) RemoveResourceProfile(tenant, id string, transactionID string) (err error) {
key := utils.ResourceProfilesPrefix + utils.ConcatenatedKey(tenant, id)
if err = rs.Cmd("DEL", key).Err; err != nil {
return
}
@@ -1397,8 +1399,8 @@ func (rs *RedisStorage) RemoveResourceProfile(id string, transactionID string) (
return
}
func (rs *RedisStorage) GetResource(id string, skipCache bool, transactionID string) (r *Resource, err error) {
key := utils.ResourcesPrefix + id
func (rs *RedisStorage) GetResource(tenant, id string, skipCache bool, transactionID string) (r *Resource, err error) {
key := utils.ResourcesPrefix + utils.ConcatenatedKey(tenant, id)
if !skipCache {
if x, ok := cache.Get(key); ok {
if x == nil {
@@ -1427,11 +1429,11 @@ func (rs *RedisStorage) SetResource(r *Resource) (err error) {
if err != nil {
return err
}
return rs.Cmd("SET", utils.ResourcesPrefix+r.ID, result).Err
return rs.Cmd("SET", utils.ResourcesPrefix+r.TenantID(), result).Err
}
func (rs *RedisStorage) RemoveResource(id string, transactionID string) (err error) {
key := utils.ResourcesPrefix + id
func (rs *RedisStorage) RemoveResource(tenant, id string, transactionID string) (err error) {
key := utils.ResourcesPrefix + utils.ConcatenatedKey(tenant, id)
if err = rs.Cmd("DEL", key).Err; err != nil {
return
}

View File

@@ -53,11 +53,11 @@ type TpReader struct {
cdrStats map[string]*CdrStats
users map[string]*UserProfile
aliases map[string]*Alias
resProfiles map[string]*utils.TPResource
resProfiles map[string]map[string]*utils.TPResource
sqProfiles map[string]*utils.TPStats
thresholds map[string]*utils.TPThreshold
resources []string // IDs of resources which need creation based on resourceProfiles
statQueues []string // IDs of statQueues which need creation based on statQueueProfiles
resources []*utils.TenantID // IDs of resources which need creation based on resourceProfiles
statQueues []string // IDs of statQueues which need creation based on statQueueProfiles
revDests,
revAliases,
@@ -129,7 +129,7 @@ func (tpr *TpReader) Init() {
tpr.users = make(map[string]*UserProfile)
tpr.aliases = make(map[string]*Alias)
tpr.derivedChargers = make(map[string]*utils.DerivedChargers)
tpr.resProfiles = make(map[string]*utils.TPResource)
tpr.resProfiles = make(map[string]map[string]*utils.TPResource)
tpr.sqProfiles = make(map[string]*utils.TPStats)
tpr.thresholds = make(map[string]*utils.TPThreshold)
tpr.revDests = make(map[string][]string)
@@ -1599,16 +1599,22 @@ func (tpr *TpReader) LoadResourceProfilesFiltered(tag string) error {
if err != nil {
return err
}
mapRsPs := make(map[string]*utils.TPResource)
mapRsPfls := make(map[string]map[string]*utils.TPResource)
for _, rl := range rls {
mapRsPs[rl.ID] = rl
if _, has := mapRsPfls[rl.Tenant]; !has {
mapRsPfls[rl.Tenant] = make(map[string]*utils.TPResource)
}
mapRsPfls[rl.Tenant][rl.ID] = rl
}
tpr.resProfiles = mapRsPs
for rID := range mapRsPs {
if has, err := tpr.dataStorage.HasData(utils.ResourcesPrefix, rID); err != nil {
return err
} else if !has {
tpr.resources = append(tpr.resources, rID)
tpr.resProfiles = mapRsPfls
for tenant, mpID := range mapRsPfls {
for id := range mpID {
rTid := &utils.TenantID{tenant, id}
if has, err := tpr.dataStorage.HasData(utils.ResourcesPrefix, rTid.TenantID()); err != nil {
return err
} else if !has {
tpr.resources = append(tpr.resources, rTid)
}
}
}
return nil
@@ -1952,27 +1958,29 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err
if verbose {
log.Print("ResourceProfiles:")
}
for _, tpRsp := range tpr.resProfiles {
rsp, err := APItoResource(tpRsp, tpr.timezone)
if err != nil {
return err
}
if err = tpr.dataStorage.SetResourceProfile(rsp, utils.NonTransactional); err != nil {
return err
}
if verbose {
log.Print("\t", rsp.ID)
for _, mpID := range tpr.resProfiles {
for _, tpRsp := range mpID {
rsp, err := APItoResource(tpRsp, tpr.timezone)
if err != nil {
return err
}
if err = tpr.dataStorage.SetResourceProfile(rsp, utils.NonTransactional); err != nil {
return err
}
if verbose {
log.Print("\t", rsp.TenantID())
}
}
}
if verbose {
log.Print("Resources:")
}
for _, rID := range tpr.resources {
if err = tpr.dataStorage.SetResource(&Resource{ID: rID, Usages: make(map[string]*ResourceUsage)}); err != nil {
for _, rTid := range tpr.resources {
if err = tpr.dataStorage.SetResource(&Resource{Tenant: rTid.Tenant, ID: rTid.ID, Usages: make(map[string]*ResourceUsage)}); err != nil {
return
}
if verbose {
log.Print("\t", rID)
log.Print("\t", rTid.TenantID())
}
}
if verbose {
@@ -2057,22 +2065,24 @@ func (tpr *TpReader) WriteToDatabase(flush, verbose, disable_reverse bool) (err
if verbose {
log.Print("Indexing resource profiles")
}
rlIdxr, err := NewReqFilterIndexer(tpr.dataStorage, utils.ResourceProfilesIndex)
if err != nil {
return err
}
for _, tpRL := range tpr.resProfiles {
if rl, err := APItoResource(tpRL, tpr.timezone); err != nil {
for tenant, mpID := range tpr.resProfiles {
rlIdxr, err := NewReqFilterIndexer(tpr.dataStorage, utils.ResourceProfilesIndex+tenant)
if err != nil {
return err
}
for _, tpRL := range mpID {
if rl, err := APItoResource(tpRL, tpr.timezone); err != nil {
return err
} else {
rlIdxr.IndexFilters(rl.ID, rl.Filters)
}
}
if verbose {
log.Printf("Indexed ResourceProfile tenant: %s keys: %+v", tenant, rlIdxr.ChangedKeys().Slice())
}
if err := rlIdxr.StoreIndexes(); err != nil {
return err
} else {
rlIdxr.IndexFilters(rl.ID, rl.Filters)
}
}
if verbose {
log.Printf("Indexed ResourceProfile keys: %+v", rlIdxr.ChangedKeys().Slice())
}
if err := rlIdxr.StoreIndexes(); err != nil {
return err
}
}
if len(tpr.sqProfiles) > 0 {
@@ -2294,11 +2304,11 @@ func (tpr *TpReader) GetLoadedIds(categ string) ([]string, error) {
}
return keys, nil
case utils.ResourceProfilesPrefix:
keys := make([]string, len(tpr.resProfiles))
i := 0
for k := range tpr.resProfiles {
keys[i] = k
i++
keys := make([]string, 0)
for tenant, mpID := range tpr.resProfiles {
for id := range mpID {
keys = append(keys, utils.ConcatenatedKey(tenant, id))
}
}
return keys, nil
case utils.ACTION_TRIGGER_PREFIX:

View File

@@ -759,3 +759,23 @@ func AppendToFile(fName, text string) error {
f.Close()
return nil
}
func NewTenantID(tntID string) *TenantID {
if strings.Index(tntID, CONCATENATED_KEY_SEP) == -1 { // no :, ID without Tenant
return &TenantID{ID: tntID}
}
tIDSplt := strings.Split(tntID, CONCATENATED_KEY_SEP)
if len(tIDSplt) == 1 { // only Tenant present
return &TenantID{Tenant: tIDSplt[0]}
}
return &TenantID{Tenant: tIDSplt[0], ID: tIDSplt[1]}
}
type TenantID struct {
Tenant string
ID string
}
func (tID *TenantID) TenantID() string {
return ConcatenatedKey(tID.Tenant, tID.ID)
}