New admins package

This commit is contained in:
gezimbll
2023-12-14 06:47:11 -05:00
committed by Dan Christian Bogos
parent 75cf4a75cc
commit 5e4b392bd0
15 changed files with 3408 additions and 0 deletions

163
admins/accounts.go Normal file
View File

@@ -0,0 +1,163 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/utils"
)
// GetAccount returns an Account
func (admS *AdminS) V1GetAccount(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.Account) 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 = admS.cfg.GeneralCfg().DefaultTenant
}
ap, err := admS.dm.GetAccount(ctx, tnt, arg.ID)
if err != nil {
if err.Error() != utils.ErrNotFound.Error() {
err = utils.NewErrServerError(err)
}
return err
}
*reply = *ap
return nil
}
// GetAccountIDs returns list of account profile IDs registered for a tenant
func (admS *AdminS) V1GetAccountIDs(ctx *context.Context, args *utils.ArgsItemIDs, actPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.AccountPrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*actPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetAccounts returns a list of accounts registered for a tenant
func (admS *AdminS) V1GetAccounts(ctx *context.Context, args *utils.ArgsItemIDs, accs *[]*utils.Account) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var accIDs []string
if err = admS.V1GetAccountIDs(ctx, args, &accIDs); err != nil {
return
}
*accs = make([]*utils.Account, 0, len(accIDs))
for _, accID := range accIDs {
var acc *utils.Account
acc, err = admS.dm.GetAccount(ctx, tnt, accID)
if err != nil {
return utils.APIErrorHandler(err)
}
*accs = append(*accs, acc)
}
return
}
// GetAccountsCount sets in reply var the total number of AccountIDs registered for a tenant
// returns ErrNotFound in case of 0 AccountIDs
func (admS *AdminS) V1GetAccountsCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.AccountPrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetAccount add/update a new Account
func (admS *AdminS) V1SetAccount(ctx *context.Context, args *utils.AccountWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.Account, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.SetAccount(ctx, args.Account, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheAccountProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheAccounts: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), args.Tenant, utils.CacheAccounts,
args.TenantID(), utils.EmptyString, &args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveAccount remove a specific Account
func (admS *AdminS) V1RemoveAccount(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 = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveAccount(ctx, tnt, arg.ID,
true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheAccountProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheAccounts: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheAccounts,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

165
admins/actions.go Normal file
View File

@@ -0,0 +1,165 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetActionProfile returns an Action Profile
func (admS *AdminS) V1GetActionProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.ActionProfile) 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 = admS.cfg.GeneralCfg().DefaultTenant
}
ap, err := admS.dm.GetActionProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
if err != nil {
if err.Error() != utils.ErrNotFound.Error() {
err = utils.NewErrServerError(err)
}
return err
}
*reply = *ap
return nil
}
// GetActionProfileIDs returns list of action profile IDs registered for a tenant
func (admS *AdminS) V1GetActionProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, actPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ActionProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*actPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetActionProfiles returns a list of action profiles registered for a tenant
func (admS *AdminS) V1GetActionProfiles(ctx *context.Context, args *utils.ArgsItemIDs, actPrfs *[]*engine.ActionProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var actPrfIDs []string
if err = admS.V1GetActionProfileIDs(ctx, args, &actPrfIDs); err != nil {
return
}
*actPrfs = make([]*engine.ActionProfile, 0, len(actPrfIDs))
for _, actPrfID := range actPrfIDs {
var ap *engine.ActionProfile
ap, err = admS.dm.GetActionProfile(ctx, tnt, actPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*actPrfs = append(*actPrfs, ap)
}
return
}
// GetActionProfilesCount sets in reply var the total number of ActionProfileIDs registered for a tenant
// returns ErrNotFound in case of 0 ActionProfileIDs
func (admS *AdminS) V1GetActionProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ActionProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetActionProfile add/update a new Action Profile
func (admS *AdminS) V1SetActionProfile(ctx *context.Context, ap *engine.ActionProfileWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(ap.ActionProfile, []string{utils.ID, utils.Actions}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if ap.Tenant == utils.EmptyString {
ap.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.SetActionProfile(ctx, ap.ActionProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheActionProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheActionProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(ap.APIOpts[utils.MetaCache]), ap.Tenant, utils.CacheActionProfiles,
ap.TenantID(), utils.EmptyString, &ap.FilterIDs, ap.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveActionProfile remove a specific Action Profile
func (admS *AdminS) V1RemoveActionProfile(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 = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveActionProfile(ctx, tnt, arg.ID,
true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheActionProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheActionProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheActionProfiles,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

50
admins/admins.go Normal file
View File

@@ -0,0 +1,50 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
)
func NewAdminS(cfg *config.CGRConfig, dm *engine.DataManager, connMgr *engine.ConnManager, fltrS *engine.FilterS,
storDBChan chan engine.StorDB) *AdminS {
storDB := <-storDBChan
return &AdminS{
cfg: cfg,
dm: dm,
storDB: storDB,
connMgr: connMgr,
fltrS: fltrS,
// TODO: Might be a good idea to pass the storDB channel to AdminSv1
// to be able to close the service the moment storDB is down (inside
// a ListenAndServe goroutine maybe)
// storDBChan: storDBChan,
}
}
type AdminS struct {
cfg *config.CGRConfig
dm *engine.DataManager
storDB engine.StorDB
connMgr *engine.ConnManager
fltrS *engine.FilterS
}

168
admins/attributes.go Normal file
View File

@@ -0,0 +1,168 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetAttributeProfile returns an Attribute Profile based on the tenant and ID received
func (admS *AdminS) V1GetAttributeProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.APIAttributeProfile) (err 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 = admS.cfg.GeneralCfg().DefaultTenant
}
if attrPrf, err := admS.dm.GetAttributeProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
} else {
attr := engine.NewAPIAttributeProfile(attrPrf)
*reply = *attr
}
return nil
}
// GetAttributeProfileIDs returns list of attributeProfile IDs registered for a tenant
func (admS *AdminS) V1GetAttributeProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, attrPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.AttributeProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*attrPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetAttributeProfiles returns a list of attribute profiles registered for a tenant
func (admS *AdminS) V1GetAttributeProfiles(ctx *context.Context, args *utils.ArgsItemIDs, attrPrfs *[]*engine.APIAttributeProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var attrPrfIDs []string
if err = admS.V1GetAttributeProfileIDs(ctx, args, &attrPrfIDs); err != nil {
return
}
*attrPrfs = make([]*engine.APIAttributeProfile, 0, len(attrPrfIDs))
for _, attrPrfID := range attrPrfIDs {
var ap *engine.AttributeProfile
ap, err = admS.dm.GetAttributeProfile(ctx, tnt, attrPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
attr := engine.NewAPIAttributeProfile(ap)
*attrPrfs = append(*attrPrfs, attr)
}
return
}
// GetAttributeProfilesCount returns the total number of AttributeProfileIDs registered for a tenant
// returns ErrNotFound in case of 0 AttributeProfileIDs
func (admS *AdminS) V1GetAttributeProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.AttributeProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetAttributeProfile add/update a new Attribute Profile
func (admS *AdminS) V1SetAttributeProfile(ctx *context.Context, arg *engine.APIAttributeProfileWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(arg.APIAttributeProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if arg.Tenant == utils.EmptyString {
arg.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
alsPrf, err := arg.APIAttributeProfile.AsAttributeProfile()
if err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.dm.SetAttributeProfile(ctx, alsPrf, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheAttributeProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx,
map[string]int64{utils.CacheAttributeProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), alsPrf.Tenant, utils.CacheAttributeProfiles,
alsPrf.TenantID(), utils.EmptyString, &alsPrf.FilterIDs, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveAttributeProfile remove a specific Attribute Profile based on tenant an ID
func (admS *AdminS) V1RemoveAttributeProfile(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 = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveAttributeProfile(ctx, tnt, arg.ID,
true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheAttributeProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheAttributeProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheAttributeProfiles,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

61
admins/cdrs.go Normal file
View File

@@ -0,0 +1,61 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"fmt"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetCDRs retrieves a list of CDRs matching the specified filters.
func (admS AdminS) V1GetCDRs(ctx *context.Context, args *utils.CDRFilters, reply *[]*utils.CDR) error {
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
fltrs, err := engine.GetFilters(ctx, args.FilterIDs, args.Tenant, admS.dm)
if err != nil {
return fmt.Errorf("preparing filters failed: %w", err)
}
cdrs, err := admS.storDB.GetCDRs(ctx, fltrs, args.APIOpts)
if err != nil {
return fmt.Errorf("retrieving CDRs failed: %w", err)
}
*reply = cdrs
return nil
}
// RemoveCDRs removes CDRs matching the specified filters.
func (admS AdminS) V1RemoveCDRs(ctx *context.Context, args *utils.CDRFilters, reply *string) (err error) {
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
fltrs, err := engine.GetFilters(ctx, args.FilterIDs, args.Tenant, admS.dm)
if err != nil {
return fmt.Errorf("preparing filters failed: %w", err)
}
if err := admS.storDB.RemoveCDRs(ctx, fltrs); err != nil {
return fmt.Errorf("removing CDRs failed: %w", err)
}
*reply = utils.OK
return
}

169
admins/chargers.go Normal file
View File

@@ -0,0 +1,169 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetChargerProfile returns a Charger Profile
func (adms *AdminS) V1GetChargerProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.ChargerProfile) 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 = adms.cfg.GeneralCfg().DefaultTenant
}
if cpp, err := adms.dm.GetChargerProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
} else {
*reply = *cpp
}
return nil
}
// GetChargerProfileIDs returns list of chargerProfile IDs registered for a tenant
func (adms *AdminS) V1GetChargerProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, chPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ChargerProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*chPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetChargerProfiles returns a list of charger profiles registered for a tenant
func (admS *AdminS) V1GetChargerProfiles(ctx *context.Context, args *utils.ArgsItemIDs, chrgPrfs *[]*engine.ChargerProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var chrgPrfIDs []string
if err = admS.V1GetChargerProfileIDs(ctx, args, &chrgPrfIDs); err != nil {
return
}
*chrgPrfs = make([]*engine.ChargerProfile, 0, len(chrgPrfIDs))
for _, chrgPrfID := range chrgPrfIDs {
var chgrPrf *engine.ChargerProfile
chgrPrf, err = admS.dm.GetChargerProfile(ctx, tnt, chrgPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*chrgPrfs = append(*chrgPrfs, chgrPrf)
}
return
}
// GetChargerProfilesCount returns the total number of ChargerProfiles registered for a tenant
// returns ErrNotFound in case of 0 ChargerProfiles
func (admS *AdminS) V1GetChargerProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ChargerProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
type ChargerWithAPIOpts struct {
*engine.ChargerProfile
APIOpts map[string]any
}
// SetChargerProfile add/update a new Charger Profile
func (adms *AdminS) V1SetChargerProfile(ctx *context.Context, arg *ChargerWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(arg.ChargerProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if arg.Tenant == utils.EmptyString {
arg.Tenant = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.SetChargerProfile(ctx, arg.ChargerProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheChargerProfiles and store it in database
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheChargerProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for ChargerProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), arg.Tenant, utils.CacheChargerProfiles,
arg.TenantID(), utils.EmptyString, &arg.FilterIDs, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveChargerProfile remove a specific Charger Profile
func (adms *AdminS) V1RemoveChargerProfile(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 = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.RemoveChargerProfile(ctx, tnt,
arg.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheChargerProfiles and store it in database
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheChargerProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for ChargerProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheChargerProfiles,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

316
admins/dispatchers.go Normal file
View File

@@ -0,0 +1,316 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetDispatcherProfile returns a Dispatcher Profile
func (admS *AdminS) V1GetDispatcherProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.DispatcherProfile) 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 = admS.cfg.GeneralCfg().DefaultTenant
}
dpp, err := admS.dm.GetDispatcherProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*reply = *dpp
return nil
}
// GetDispatcherProfileIDs returns list of dispatcherProfile IDs registered for a tenant
func (admS *AdminS) V1GetDispatcherProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, dPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.DispatcherProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*dPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetDispatcherProfiles returns a list of dispatcher profiles registered for a tenant
func (admS *AdminS) V1GetDispatcherProfiles(ctx *context.Context, args *utils.ArgsItemIDs, dspPrfs *[]*engine.DispatcherProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var dspPrfIDs []string
if err = admS.V1GetDispatcherProfileIDs(ctx, args, &dspPrfIDs); err != nil {
return
}
*dspPrfs = make([]*engine.DispatcherProfile, 0, len(dspPrfIDs))
for _, dspPrfID := range dspPrfIDs {
var dspPrf *engine.DispatcherProfile
dspPrf, err = admS.dm.GetDispatcherProfile(ctx, tnt, dspPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*dspPrfs = append(*dspPrfs, dspPrf)
}
return
}
// GetDispatcherProfilesCount returns the total number of DispatcherProfiles registered for a tenant
// returns ErrNotFound in case of 0 DispatcherProfiles
func (admS *AdminS) V1GetDispatcherProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.DispatcherProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
type DispatcherWithAPIOpts struct {
*engine.DispatcherProfile
APIOpts map[string]any
}
// SetDispatcherProfile add/update a new Dispatcher Profile
func (admS *AdminS) V1SetDispatcherProfile(ctx *context.Context, args *DispatcherWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.DispatcherProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.SetDispatcherProfile(ctx, args.DispatcherProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheDispatcherProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheDispatcherProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for DispatcherProfile
if err := admS.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), args.Tenant, utils.CacheDispatcherProfiles,
args.TenantID(), utils.EmptyString, &args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for DispatchersInstance
cacheAct := utils.MetaRemove
if err := admS.CallCache(ctx, utils.FirstNonEmpty(utils.IfaceAsString(args.APIOpts[utils.MetaCache]), cacheAct),
args.Tenant, utils.CacheDispatchers, args.TenantID(), utils.EmptyString, &args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for DispatcherRoutes
if err := admS.CallCache(ctx, utils.FirstNonEmpty(utils.IfaceAsString(args.APIOpts[utils.MetaCache]), cacheAct),
args.Tenant, utils.CacheDispatcherRoutes, args.TenantID(),
utils.ConcatenatedKey(utils.CacheDispatcherProfiles, args.Tenant, args.ID),
&args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveDispatcherProfile remove a specific Dispatcher Profile
func (admS *AdminS) V1RemoveDispatcherProfile(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 = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveDispatcherProfile(ctx, tnt,
arg.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheDispatcherProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheDispatcherProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for DispatcherProfile
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheDispatcherProfiles,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// GetDispatcherHost returns a Dispatcher Host
func (admS *AdminS) V1GetDispatcherHost(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.DispatcherHost) 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 = admS.cfg.GeneralCfg().DefaultTenant
}
dpp, err := admS.dm.GetDispatcherHost(ctx, tnt, arg.ID, true, false, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*reply = *dpp
return nil
}
// GetDispatcherHostIDs returns list of dispatcherHost IDs registered for a tenant
func (admS *AdminS) V1GetDispatcherHostIDs(ctx *context.Context, args *utils.ArgsItemIDs, dspHostIDs *[]string) (err error) {
tenant := args.Tenant
if tenant == utils.EmptyString {
tenant = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.DispatcherHostPrefix + tenant + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); 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:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*dspHostIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetDispatcherHosts returns a list of dispatcher hosts registered for a tenant
func (admS *AdminS) V1GetDispatcherHosts(ctx *context.Context, args *utils.ArgsItemIDs, dspHosts *[]*engine.DispatcherHost) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var dspHostIDs []string
if err = admS.V1GetDispatcherHostIDs(ctx, args, &dspHostIDs); err != nil {
return
}
*dspHosts = make([]*engine.DispatcherHost, 0, len(dspHostIDs))
for _, dspHostID := range dspHostIDs {
var dspHost *engine.DispatcherHost
dspHost, err = admS.dm.GetDispatcherHost(ctx, tnt, dspHostID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*dspHosts = append(*dspHosts, dspHost)
}
return
}
// GetDispatcherHostsCount returns the total number of DispatcherHosts registered for a tenant
// returns ErrNotFound in case of 0 DispatcherHosts
func (admS *AdminS) V1GetDispatcherHostsCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.DispatcherHostPrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetDispatcherHost add/update a new Dispatcher Host
func (admS *AdminS) V1SetDispatcherHost(ctx *context.Context, args *engine.DispatcherHostWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.DispatcherHost, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.SetDispatcherHost(ctx, args.DispatcherHost); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheDispatcherHosts and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheDispatcherHosts: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for DispatcherProfile
if err := admS.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), args.Tenant, utils.CacheDispatcherHosts,
args.TenantID(), utils.EmptyString, nil, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveDispatcherHost remove a specific Dispatcher Host
func (admS *AdminS) V1RemoveDispatcherHost(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 = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveDispatcherHost(ctx, tnt, arg.ID); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheDispatcherHosts and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheDispatcherHosts: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for DispatcherProfile
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheDispatcherHosts,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

842
admins/filter_indexes.go Normal file
View File

@@ -0,0 +1,842 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"slices"
"strings"
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/ltcache"
)
type AttrGetFilterIndexes struct {
Tenant string
Context string
ItemType string
FilterType string
FilterField string
FilterValue string
APIOpts map[string]any
}
type AttrRemFilterIndexes struct {
Tenant string
Context string
ItemType string
APIOpts map[string]any
}
func (adms *AdminS) V1RemoveFilterIndexes(ctx *context.Context, arg *AttrRemFilterIndexes, reply *string) (err error) {
if missing := utils.MissingStructFields(arg, []string{"ItemType"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
tnt := arg.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
tntCtx := tnt
switch arg.ItemType {
case utils.MetaThresholds:
arg.ItemType = utils.CacheThresholdFilterIndexes
case utils.MetaRoutes:
arg.ItemType = utils.CacheRouteFilterIndexes
case utils.MetaStats:
arg.ItemType = utils.CacheStatFilterIndexes
case utils.MetaResources:
arg.ItemType = utils.CacheResourceFilterIndexes
case utils.MetaChargers:
arg.ItemType = utils.CacheChargerFilterIndexes
case utils.MetaAccounts:
arg.ItemType = utils.CacheAccountsFilterIndexes
case utils.MetaActions:
arg.ItemType = utils.CacheActionProfilesFilterIndexes
case utils.MetaRateProfiles:
arg.ItemType = utils.CacheRateProfilesFilterIndexes
case utils.MetaRateProfileRates:
if missing := utils.MissingStructFields(arg, []string{"Context"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
arg.ItemType = utils.CacheRateFilterIndexes
tntCtx = utils.ConcatenatedKey(tnt, arg.Context)
case utils.MetaDispatchers:
arg.ItemType = utils.CacheDispatcherFilterIndexes
case utils.MetaAttributes:
arg.ItemType = utils.CacheAttributeFilterIndexes
}
if err = adms.dm.RemoveIndexes(ctx, arg.ItemType, tntCtx, utils.EmptyString); err != nil {
return
}
//generate a loadID for CacheFilterIndexes and store it in database
if err := adms.dm.SetLoadIDs(ctx,
map[string]int64{arg.ItemType: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := adms.callCacheForRemoveIndexes(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), arg.Tenant,
arg.ItemType, []string{utils.MetaAny}, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return
}
func (adms *AdminS) V1GetFilterIndexes(ctx *context.Context, arg *AttrGetFilterIndexes, reply *[]string) (err error) {
var indexes map[string]utils.StringSet
var indexedSlice []string
indexesFilter := make(map[string]utils.StringSet)
if missing := utils.MissingStructFields(arg, []string{"ItemType"}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
tnt := arg.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
tntCtx := tnt
switch arg.ItemType {
case utils.MetaThresholds:
arg.ItemType = utils.CacheThresholdFilterIndexes
case utils.MetaRoutes:
arg.ItemType = utils.CacheRouteFilterIndexes
case utils.MetaStats:
arg.ItemType = utils.CacheStatFilterIndexes
case utils.MetaResources:
arg.ItemType = utils.CacheResourceFilterIndexes
case utils.MetaChargers:
arg.ItemType = utils.CacheChargerFilterIndexes
case utils.MetaAccounts:
arg.ItemType = utils.CacheAccountsFilterIndexes
case utils.MetaActions:
arg.ItemType = utils.CacheActionProfilesFilterIndexes
case utils.MetaRateProfiles:
arg.ItemType = utils.CacheRateProfilesFilterIndexes
case utils.MetaRateProfileRates:
if missing := utils.MissingStructFields(arg, []string{"Context"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
arg.ItemType = utils.CacheRateFilterIndexes
tntCtx = utils.ConcatenatedKey(tnt, arg.Context)
case utils.MetaDispatchers:
arg.ItemType = utils.CacheDispatcherFilterIndexes
case utils.MetaAttributes:
arg.ItemType = utils.CacheAttributeFilterIndexes
}
if indexes, err = adms.dm.GetIndexes(ctx,
arg.ItemType, tntCtx, utils.EmptyString, utils.EmptyString, true, true); err != nil {
return
}
if arg.FilterType != utils.EmptyString {
for val, strmap := range indexes {
if strings.HasPrefix(val, arg.FilterType) {
indexesFilter[val] = strmap
for _, value := range strmap.AsSlice() {
indexedSlice = append(indexedSlice, utils.ConcatenatedKey(val, value))
}
}
}
if len(indexedSlice) == 0 {
return utils.ErrNotFound
}
}
if arg.FilterField != utils.EmptyString {
if len(indexedSlice) == 0 {
indexesFilter = make(map[string]utils.StringSet)
for val, strmap := range indexes {
if strings.Contains(val, arg.FilterField) {
indexesFilter[val] = strmap
for _, value := range strmap.AsSlice() {
indexedSlice = append(indexedSlice, utils.ConcatenatedKey(val, value))
}
}
}
if len(indexedSlice) == 0 {
return utils.ErrNotFound
}
} else {
var cloneIndexSlice []string
for val, strmap := range indexesFilter {
if strings.Contains(val, arg.FilterField) {
for _, value := range strmap.AsSlice() {
cloneIndexSlice = append(cloneIndexSlice, utils.ConcatenatedKey(val, value))
}
}
}
if len(cloneIndexSlice) == 0 {
return utils.ErrNotFound
}
indexedSlice = cloneIndexSlice
}
}
if arg.FilterValue != utils.EmptyString {
if len(indexedSlice) == 0 {
for val, strmap := range indexes {
if strings.Contains(val, arg.FilterValue) {
for _, value := range strmap.AsSlice() {
indexedSlice = append(indexedSlice, utils.ConcatenatedKey(val, value))
}
}
}
if len(indexedSlice) == 0 {
return utils.ErrNotFound
}
} else {
var cloneIndexSlice []string
for val, strmap := range indexesFilter {
if strings.Contains(val, arg.FilterValue) {
for _, value := range strmap.AsSlice() {
cloneIndexSlice = append(cloneIndexSlice, utils.ConcatenatedKey(val, value))
}
}
}
if len(cloneIndexSlice) == 0 {
return utils.ErrNotFound
}
indexedSlice = cloneIndexSlice
}
}
if len(indexedSlice) == 0 {
for val, strmap := range indexes {
for _, value := range strmap.AsSlice() {
indexedSlice = append(indexedSlice, utils.ConcatenatedKey(val, value))
}
}
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(arg.APIOpts); err != nil {
return
}
*reply, err = utils.Paginate(indexedSlice, limit, offset, maxItems)
return
}
// ComputeFilterIndexes selects which index filters to recompute
func (adms *AdminS) V1ComputeFilterIndexes(ctx *context.Context, args *utils.ArgsComputeFilterIndexes, reply *string) (err error) {
transactionID := utils.GenUUID()
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
cacheIDs := make(map[string][]string)
var indexes utils.StringSet
//ThresholdProfile Indexes
if args.ThresholdS {
cacheIDs[utils.CacheThresholdFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheThresholdFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
th, e := adms.dm.GetThresholdProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(th.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.ThresholdS = indexes.Size() != 0
}
//StatQueueProfile Indexes
if args.StatS {
cacheIDs[utils.CacheStatFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheStatFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
sq, e := adms.dm.GetStatQueueProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(sq.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.StatS = indexes.Size() != 0
}
//ResourceProfile Indexes
if args.ResourceS {
cacheIDs[utils.CacheResourceFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheResourceFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
rp, e := adms.dm.GetResourceProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(rp.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.ResourceS = indexes.Size() != 0
}
//RouteSProfile Indexes
if args.RouteS {
cacheIDs[utils.CacheRouteFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheRouteFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
rp, e := adms.dm.GetRouteProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(rp.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.RouteS = indexes.Size() != 0
}
//AttributeProfile Indexes
if args.AttributeS {
cacheIDs[utils.CacheAttributeFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheAttributeFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
attr, e := adms.dm.GetAttributeProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(attr.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.AttributeS = indexes.Size() != 0
}
//ChargerProfile Indexes
if args.ChargerS {
cacheIDs[utils.CacheChargerFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheChargerFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
ch, e := adms.dm.GetChargerProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(ch.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.ChargerS = indexes.Size() != 0
}
//AccountFilter Indexes
if args.AccountS {
cacheIDs[utils.CacheAccountsFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheAccountsFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
acnts, e := adms.dm.GetAccount(ctx, tnt, id)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(acnts.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.AccountS = indexes.Size() != 0
}
//ActionFilter Indexes
if args.ActionS {
cacheIDs[utils.CacheActionProfilesFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheActionProfilesFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
act, e := adms.dm.GetActionProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(act.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
args.ActionS = indexes.Size() != 0
}
// RateFilter Indexes
var ratePrf []string
if args.RateS {
cacheIDs[utils.CacheRateProfilesFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheRateProfilesFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
rtPrf, e := adms.dm.GetRateProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
ratePrf = append(ratePrf, utils.ConcatenatedKey(tnt, id))
rtIds := make([]string, 0, len(rtPrf.Rates))
for key := range rtPrf.Rates {
rtIds = append(rtIds, key)
}
cacheIDs[utils.CacheRateFilterIndexes] = rtIds
_, e = engine.ComputeIndexes(ctx, adms.dm, tnt, id, utils.CacheRateFilterIndexes,
&rtIds, transactionID, func(_, id, _ string) (*[]string, error) {
return utils.SliceStringPointer(slices.Clone(rtPrf.Rates[id].FilterIDs)), nil
}, nil)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(rtPrf.FilterIDs)), nil
}, nil); err != nil {
return utils.APIErrorHandler(err)
}
args.RateS = indexes.Size() != 0
}
//DispatcherProfile Indexes
if args.DispatcherS {
cacheIDs[utils.CacheDispatcherFilterIndexes] = []string{utils.MetaAny}
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheDispatcherFilterIndexes,
nil, transactionID, func(tnt, id, grp string) (*[]string, error) {
dsp, e := adms.dm.GetDispatcherProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(dsp.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrDSPProfileNotFound {
return utils.APIErrorHandler(err)
}
args.DispatcherS = indexes.Size() != 0
}
//Now we move from tmpKey to the right key for each type
//ThresholdProfile Indexes
if args.ThresholdS {
if err = adms.dm.SetIndexes(ctx, utils.CacheThresholdFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//StatQueueProfile Indexes
if args.StatS {
if err = adms.dm.SetIndexes(ctx, utils.CacheStatFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//ResourceProfile Indexes
if args.ResourceS {
if err = adms.dm.SetIndexes(ctx, utils.CacheResourceFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//RouteProfile Indexes
if args.RouteS {
if err = adms.dm.SetIndexes(ctx, utils.CacheRouteFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//AttributeProfile Indexes
if args.AttributeS {
if err = adms.dm.SetIndexes(ctx, utils.CacheAttributeFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//ChargerProfile Indexes
if args.ChargerS {
if err = adms.dm.SetIndexes(ctx, utils.CacheChargerFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//AccountProfile Indexes
if args.AccountS {
if err = adms.dm.SetIndexes(ctx, utils.CacheAccountsFilterIndexes, tnt, nil, true, transactionID); err != nil {
return err
}
}
//ActionProfile Indexes
if args.ActionS {
if err = adms.dm.SetIndexes(ctx, utils.CacheActionProfilesFilterIndexes, tnt, nil, true, transactionID); err != nil {
return err
}
}
//RateProfile Indexes
if args.RateS {
if err = adms.dm.SetIndexes(ctx, utils.CacheRateProfilesFilterIndexes, tnt, nil, true, transactionID); err != nil {
return err
}
for _, tntId := range ratePrf {
if err = adms.dm.SetIndexes(ctx, utils.CacheRateFilterIndexes, tntId, nil, true, transactionID); err != nil {
return err
}
}
}
//DispatcherProfile Indexes
if args.DispatcherS {
if err = adms.dm.SetIndexes(ctx, utils.CacheDispatcherFilterIndexes, tnt, nil, true, transactionID); err != nil {
return
}
}
//generate a load
//ID for CacheFilterIndexes and store it in database
loadIDs := make(map[string]int64)
timeNow := time.Now().UnixNano()
for idx := range cacheIDs {
loadIDs[idx] = timeNow
}
if err := adms.dm.SetLoadIDs(ctx, loadIDs); err != nil {
return utils.APIErrorHandler(err)
}
if err := adms.callCacheForComputeIndexes(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]),
args.Tenant, cacheIDs, args.APIOpts); err != nil {
return err
}
*reply = utils.OK
return nil
}
// ComputeFilterIndexIDs computes specific filter indexes
func (adms *AdminS) V1ComputeFilterIndexIDs(ctx *context.Context, args *utils.ArgsComputeFilterIndexIDs, reply *string) (err error) {
transactionID := utils.NonTransactional
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
var indexes utils.StringSet
cacheIDs := make(map[string][]string)
//ThresholdProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheThresholdFilterIndexes,
&args.ThresholdIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
th, e := adms.dm.GetThresholdProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(th.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheThresholdFilterIndexes] = indexes.AsSlice()
}
//StatQueueProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheStatFilterIndexes,
&args.StatIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
sq, e := adms.dm.GetStatQueueProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
cacheIDs[utils.CacheStatFilterIndexes] = []string{sq.ID}
return utils.SliceStringPointer(slices.Clone(sq.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheStatFilterIndexes] = indexes.AsSlice()
}
//ResourceProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheResourceFilterIndexes,
&args.ResourceIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
rp, e := adms.dm.GetResourceProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
cacheIDs[utils.CacheResourceFilterIndexes] = []string{rp.ID}
return utils.SliceStringPointer(slices.Clone(rp.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheResourceFilterIndexes] = indexes.AsSlice()
}
//RouteProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheRouteFilterIndexes,
&args.RouteIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
rp, e := adms.dm.GetRouteProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
cacheIDs[utils.CacheRouteFilterIndexes] = []string{rp.ID}
return utils.SliceStringPointer(slices.Clone(rp.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheRouteFilterIndexes] = indexes.AsSlice()
}
//AttributeProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheAttributeFilterIndexes,
&args.AttributeIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
attr, e := adms.dm.GetAttributeProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(attr.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheAttributeFilterIndexes] = indexes.AsSlice()
}
//ChargerProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheChargerFilterIndexes,
&args.ChargerIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
ch, e := adms.dm.GetChargerProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(ch.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheChargerFilterIndexes] = indexes.AsSlice()
}
//AccountIndexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheAccountsFilterIndexes,
&args.AccountIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
acc, e := adms.dm.GetAccount(ctx, tnt, id)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(acc.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheAccountsFilterIndexes] = indexes.AsSlice()
}
//ActionProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheActionProfilesFilterIndexes,
&args.ActionProfileIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
act, e := adms.dm.GetActionProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(act.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheActionProfilesFilterIndexes] = indexes.AsSlice()
}
//RateProfile Indexes
var ratePrf []string
if _, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheRateProfilesFilterIndexes,
&args.RateProfileIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
rpr, e := adms.dm.GetRateProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
ratePrf = append(ratePrf, utils.ConcatenatedKey(tnt, id))
rtIds := make([]string, 0, len(rpr.Rates))
for key := range rpr.Rates {
rtIds = append(rtIds, key)
}
indexesRate, e := engine.ComputeIndexes(ctx, adms.dm, tnt, id, utils.CacheRateFilterIndexes,
&rtIds, transactionID, func(_, id, _ string) (*[]string, error) {
return utils.SliceStringPointer(slices.Clone(rpr.Rates[id].FilterIDs)), nil
}, nil)
if e != nil {
return nil, e
}
if indexesRate.Size() != 0 {
cacheIDs[utils.CacheRateFilterIndexes] = indexesRate.AsSlice()
}
return utils.SliceStringPointer(slices.Clone(rpr.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheRateProfilesFilterIndexes] = indexes.AsSlice()
}
//DispatcherProfile Indexes
if indexes, err = engine.ComputeIndexes(ctx, adms.dm, tnt, utils.EmptyString, utils.CacheDispatcherFilterIndexes,
&args.DispatcherIDs, transactionID, func(tnt, id, grp string) (*[]string, error) {
dsp, e := adms.dm.GetDispatcherProfile(ctx, tnt, id, true, false, utils.NonTransactional)
if e != nil {
return nil, e
}
return utils.SliceStringPointer(slices.Clone(dsp.FilterIDs)), nil
}, nil); err != nil && err != utils.ErrDSPProfileNotFound {
return utils.APIErrorHandler(err)
}
if indexes.Size() != 0 {
cacheIDs[utils.CacheDispatcherFilterIndexes] = indexes.AsSlice()
}
//generate a load
//ID for CacheFilterIndexes and store it in database
loadIDs := make(map[string]int64)
timeNow := time.Now().UnixNano()
for idx := range cacheIDs {
loadIDs[idx] = timeNow
}
if err := adms.dm.SetLoadIDs(ctx, loadIDs); err != nil {
return utils.APIErrorHandler(err)
}
if err := adms.callCacheForComputeIndexes(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]),
args.Tenant, cacheIDs, args.APIOpts); err != nil {
return err
}
*reply = utils.OK
return nil
}
func (adms *AdminS) V1GetReverseFilterHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *map[string]*engine.ReverseFilterIHReply) (err error) {
objCaches := map[string]*ltcache.Cache{utils.CacheRateFilterIndexes: ltcache.NewCache(-1, 0, false, nil)}
for indxType := range utils.CacheIndexesToPrefix {
objCaches[indxType] = ltcache.NewCache(-1, 0, false, nil)
}
*reply, err = engine.GetRevFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
objCaches,
)
return
}
func (adms *AdminS) V1GetThresholdsIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheThresholdFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetResourcesIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheResourceFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetStatsIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheStatFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetRoutesIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheRouteFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetAttributesIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheAttributeFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetChargersIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheChargerFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetDispatchersIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheDispatcherFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetRateProfilesIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheRateProfilesFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetActionsIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheActionProfilesFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetAccountsIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealth(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
utils.CacheAccountsFilterIndexes,
)
if err != nil {
return err
}
*reply = *rp
return nil
}
func (adms *AdminS) V1GetRateRatesIndexesHealth(ctx *context.Context, args *engine.IndexHealthArgs, reply *engine.FilterIHReply) error {
rp, err := engine.GetFltrIdxHealthForRateRates(ctx, adms.dm,
ltcache.NewCache(args.FilterCacheLimit, args.FilterCacheTTL, args.FilterCacheStaticTTL, nil),
ltcache.NewCache(args.IndexCacheLimit, args.IndexCacheTTL, args.IndexCacheStaticTTL, nil),
ltcache.NewCache(args.ObjectCacheLimit, args.ObjectCacheTTL, args.ObjectCacheStaticTTL, nil),
)
if err != nil {
return err
}
*reply = *rp
return nil
}

210
admins/filters.go Normal file
View File

@@ -0,0 +1,210 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"fmt"
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
func validateFilterRules(rules []*engine.FilterRule) error {
for _, rule := range rules {
if !rule.IsValid() {
return fmt.Errorf("there exists at least one filter rule that is not valid")
}
}
return nil
}
// SetFilter add a new Filter
func (adms *AdminS) V1SetFilter(ctx *context.Context, arg *engine.FilterWithAPIOpts, reply *string) (err error) {
if missing := utils.MissingStructFields(arg.Filter, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if len(arg.Rules) == 0 {
return utils.NewErrMandatoryIeMissing("Filter Rules")
}
if err = validateFilterRules(arg.Rules); err != nil {
return utils.APIErrorHandler(err)
}
if arg.Tenant == utils.EmptyString {
arg.Tenant = adms.cfg.GeneralCfg().DefaultTenant
}
tntID := arg.TenantID()
argC := map[string][]string{utils.CacheFilters: {tntID}}
if fltr, err := adms.dm.GetFilter(ctx, arg.Filter.Tenant, arg.Filter.ID, true, false, utils.NonTransactional); err != nil {
if err != utils.ErrNotFound {
return utils.APIErrorHandler(err)
}
} else if argC, err = composeCacheArgsForFilter(adms.dm, ctx, fltr, fltr.Tenant, tntID, argC); err != nil {
return utils.APIErrorHandler(err)
}
if err := adms.dm.SetFilter(ctx, arg.Filter, true); err != nil {
return utils.APIErrorHandler(err)
}
if argC, err = composeCacheArgsForFilter(adms.dm, ctx, arg.Filter, arg.Filter.Tenant, tntID, argC); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheFilters and store it in database
if err := adms.dm.SetLoadIDs(ctx,
map[string]int64{utils.CacheFilters: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for Filter
if err := callCacheForFilter(adms.connMgr, adms.cfg.AdminSCfg().CachesConns, ctx,
utils.IfaceAsString(arg.APIOpts[utils.MetaCache]),
adms.cfg.GeneralCfg().DefaultCaching,
arg.Tenant, argC, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return
}
// GetFilter returns a Filter
func (adms *AdminS) V1GetFilter(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.Filter) 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 = adms.cfg.GeneralCfg().DefaultTenant
}
if fltr, err := adms.dm.GetFilter(ctx, tnt, arg.ID, true, true, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
} else {
*reply = *fltr
}
return nil
}
// GetFilters returns a list of filters for a tenant
func (adms *AdminS) V1GetFilters(ctx *context.Context, args *utils.ArgsItemIDs, fltrs *[]*engine.Filter) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
var fltrIDs []string
if err = adms.V1GetFilterIDs(ctx, args, &fltrIDs); err != nil {
return
}
*fltrs = make([]*engine.Filter, 0, len(fltrIDs))
for _, fltrID := range fltrIDs {
var fltr *engine.Filter
if fltr, err = adms.dm.GetFilter(ctx, tnt, fltrID, true, true, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
}
*fltrs = append(*fltrs, fltr)
}
return
}
// GetFilterIDs returns list of Filter IDs registered for a tenant
func (adms *AdminS) V1GetFilterIDs(ctx *context.Context, args *utils.ArgsItemIDs, fltrIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.FilterPrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*fltrIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// RemoveFilter remove a specific filter
func (adms *AdminS) V1RemoveFilter(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 = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.RemoveFilter(ctx, tnt, arg.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheFilters and store it in database
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheFilters: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for Filter
if err := callCacheForFilter(adms.connMgr, adms.cfg.AdminSCfg().CachesConns, ctx,
utils.IfaceAsString(arg.APIOpts[utils.MetaCache]),
adms.cfg.GeneralCfg().DefaultCaching,
arg.Tenant, map[string][]string{utils.CacheFilters: {utils.ConcatenatedKey(tnt, arg.ID)}}, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// GetFiltersCount returns the total number of FilterIDs registered for a tenant
// returns ErrNotFound in case of 0 FilterIDs
func (admS *AdminS) V1GetFiltersCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.FilterPrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// FiltersMatch checks whether a set of filter IDs passes for the provided CGREvent
func (admS *AdminS) V1FiltersMatch(ctx *context.Context, args *engine.ArgsFiltersMatch, reply *bool) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
evDP := args.CGREvent.AsDataProvider()
var pass bool
if pass, err = admS.fltrS.Pass(ctx, tnt, args.FilterIDs, evDP); err != nil {
return
} else if pass {
*reply = true
}
return
}

307
admins/libadmin.go Normal file
View File

@@ -0,0 +1,307 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"strings"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// CallCache caching the item based on CacheOpt
func (admS *AdminS) CallCache(ctx *context.Context, cacheopt string, tnt, cacheID, itemID, groupID string,
filters *[]string, opts map[string]any) (err error) {
var reply, method string
var args any
switch utils.FirstNonEmpty(cacheopt, admS.cfg.GeneralCfg().DefaultCaching) {
case utils.MetaNone:
return
case utils.MetaReload:
method = utils.CacheSv1ReloadCache
var argCache map[string][]string
if argCache, err = admS.composeArgsReload(ctx, tnt, cacheID, itemID, filters); err != nil {
return
}
args = utils.NewAttrReloadCacheWithOptsFromMap(argCache, tnt, opts)
case utils.MetaLoad:
method = utils.CacheSv1LoadCache
var argCache map[string][]string
if argCache, err = admS.composeArgsReload(ctx, tnt, cacheID, itemID, filters); err != nil {
return
}
args = utils.NewAttrReloadCacheWithOptsFromMap(argCache, tnt, opts)
case utils.MetaRemove:
if groupID != utils.EmptyString {
method = utils.CacheSv1RemoveGroup
args = &utils.ArgsGetGroupWithAPIOpts{
Tenant: tnt,
APIOpts: opts,
ArgsGetGroup: utils.ArgsGetGroup{
CacheID: cacheID,
GroupID: groupID,
},
}
break
}
method = utils.CacheSv1RemoveItems
var argCache map[string][]string
if argCache, err = admS.composeArgsReload(ctx, tnt, cacheID, itemID, filters); err != nil {
return
}
args = utils.NewAttrReloadCacheWithOptsFromMap(argCache, tnt, opts)
case utils.MetaClear:
cacheIDs := make([]string, 1, 3)
cacheIDs[0] = cacheID
// do not send a EmptyString if the item doesn't have indexes
if cIdx, has := utils.CacheInstanceToCacheIndex[cacheID]; has {
cacheIDs = append(cacheIDs, cIdx)
}
switch cacheID { // add the items to the cache reload
case utils.CacheThresholdProfiles:
cacheIDs = append(cacheIDs, utils.CacheThresholds)
case utils.CacheResourceProfiles:
cacheIDs = append(cacheIDs, utils.CacheResources)
case utils.CacheStatQueueProfiles:
cacheIDs = append(cacheIDs, utils.CacheStatQueues)
}
method = utils.CacheSv1Clear
args = &utils.AttrCacheIDsWithAPIOpts{
Tenant: tnt,
CacheIDs: cacheIDs,
APIOpts: opts,
}
}
return admS.connMgr.Call(ctx, admS.cfg.AdminSCfg().CachesConns,
method, args, &reply)
}
// composeArgsReload add the ItemID to AttrReloadCache
// for a specific CacheID
func (admS *AdminS) composeArgsReload(ctx *context.Context, tnt, cacheID, itemID string, filterIDs *[]string) (argCache map[string][]string, err error) {
argCache = map[string][]string{cacheID: {itemID}}
switch cacheID { // add the items to the cache reload
case utils.CacheThresholdProfiles:
argCache[utils.CacheThresholds] = []string{itemID}
case utils.CacheResourceProfiles:
argCache[utils.CacheResources] = []string{itemID}
case utils.CacheStatQueueProfiles:
argCache[utils.CacheStatQueues] = []string{itemID}
}
if filterIDs == nil { // in case we remove a profile we do not need to reload the indexes
return
}
// populate the indexes
idxCacheID := utils.CacheInstanceToCacheIndex[cacheID]
if len(*filterIDs) == 0 { // in case we do not have any filters reload the *none filter indexes
indxID := utils.ConcatenatedKey(utils.MetaNone, utils.MetaAny, utils.MetaAny)
argCache[idxCacheID] = []string{utils.ConcatenatedKey(tnt, indxID)}
return
}
indxIDs := make([]string, 0, len(*filterIDs))
for _, id := range *filterIDs {
var fltr *engine.Filter
if fltr, err = admS.dm.GetFilter(ctx, tnt, id, true, true, utils.NonTransactional); err != nil {
return
}
for _, flt := range fltr.Rules {
if !engine.FilterIndexTypes.Has(flt.Type) ||
engine.IsDynamicDPPath(flt.Element) {
continue
}
isDyn := strings.HasPrefix(flt.Element, utils.DynamicDataPrefix)
for _, fldVal := range flt.Values {
if engine.IsDynamicDPPath(fldVal) {
continue
}
if isDyn {
if !strings.HasPrefix(fldVal, utils.DynamicDataPrefix) {
indxIDs = append(indxIDs, utils.ConcatenatedKey(flt.Type, flt.Element[1:], fldVal))
}
} else if strings.HasPrefix(fldVal, utils.DynamicDataPrefix) {
indxIDs = append(indxIDs, utils.ConcatenatedKey(flt.Type, fldVal[1:], flt.Element))
}
}
}
}
argCache[idxCacheID] = make([]string, len(indxIDs))
for i, indxID := range indxIDs {
argCache[idxCacheID][i] = utils.ConcatenatedKey(tnt, indxID)
}
return
}
// callCacheForIndexes will only call CacheClear because don't have access at ItemID
func (admS *AdminS) callCacheForRemoveIndexes(ctx *context.Context, cacheopt string, tnt, cacheID string,
itemIDs []string, opts map[string]any) (err error) {
var reply, method string
var args any = utils.NewAttrReloadCacheWithOptsFromMap(map[string][]string{cacheID: itemIDs}, tnt, opts)
switch utils.FirstNonEmpty(cacheopt, admS.cfg.GeneralCfg().DefaultCaching) {
case utils.MetaNone:
return
case utils.MetaReload:
method = utils.CacheSv1ReloadCache
case utils.MetaLoad:
method = utils.CacheSv1LoadCache
case utils.MetaRemove:
method = utils.CacheSv1RemoveItems
case utils.MetaClear:
method = utils.CacheSv1Clear
args = &utils.AttrCacheIDsWithAPIOpts{
Tenant: tnt,
CacheIDs: []string{cacheID},
APIOpts: opts,
}
}
return admS.connMgr.Call(ctx, admS.cfg.AdminSCfg().CachesConns,
method, args, &reply)
}
func (admS *AdminS) callCacheForComputeIndexes(ctx *context.Context, cacheopt, tnt string,
cacheItems map[string][]string, opts map[string]any) (err error) {
var reply, method string
var args any = utils.NewAttrReloadCacheWithOptsFromMap(cacheItems, tnt, opts)
switch utils.FirstNonEmpty(cacheopt, admS.cfg.GeneralCfg().DefaultCaching) {
case utils.MetaNone:
return
case utils.MetaReload:
method = utils.CacheSv1ReloadCache
case utils.MetaLoad:
method = utils.CacheSv1LoadCache
case utils.MetaRemove:
method = utils.CacheSv1RemoveItems
case utils.MetaClear:
method = utils.CacheSv1Clear
cacheIDs := make([]string, 0, len(cacheItems))
for idx := range cacheItems {
cacheIDs = append(cacheIDs, idx)
}
args = &utils.AttrCacheIDsWithAPIOpts{
Tenant: tnt,
CacheIDs: cacheIDs,
APIOpts: opts,
}
}
return admS.connMgr.Call(ctx, admS.cfg.AdminSCfg().CachesConns,
method, args, &reply)
}
// callCacheRevDestinations used for reverse destination, loadIDs and indexes replication
func (admS *AdminS) callCacheMultiple(ctx *context.Context, cacheopt, tnt, cacheID string, itemIDs []string, opts map[string]any) (err error) {
if len(itemIDs) == 0 {
return
}
var reply, method string
var args any
switch utils.FirstNonEmpty(cacheopt, admS.cfg.GeneralCfg().DefaultCaching) {
case utils.MetaNone:
return
case utils.MetaReload:
method = utils.CacheSv1ReloadCache
args = utils.NewAttrReloadCacheWithOptsFromMap(map[string][]string{cacheID: itemIDs}, tnt, opts)
case utils.MetaLoad:
method = utils.CacheSv1LoadCache
args = utils.NewAttrReloadCacheWithOptsFromMap(map[string][]string{cacheID: itemIDs}, tnt, opts)
case utils.MetaRemove:
method = utils.CacheSv1RemoveItems
args = utils.NewAttrReloadCacheWithOptsFromMap(map[string][]string{cacheID: itemIDs}, tnt, opts)
case utils.MetaClear:
method = utils.CacheSv1Clear
args = &utils.AttrCacheIDsWithAPIOpts{
Tenant: tnt,
CacheIDs: []string{cacheID},
APIOpts: opts,
}
}
return admS.connMgr.Call(ctx, admS.cfg.AdminSCfg().CachesConns,
method, args, &reply)
}
func composeCacheArgsForFilter(dm *engine.DataManager, ctx *context.Context, fltr *engine.Filter, tnt, tntID string, args map[string][]string) (_ map[string][]string, err error) {
indxIDs := make([]string, 0, len(fltr.Rules))
for _, flt := range fltr.Rules {
if !engine.FilterIndexTypes.Has(flt.Type) ||
engine.IsDynamicDPPath(flt.Element) {
continue
}
isDyn := strings.HasPrefix(flt.Element, utils.DynamicDataPrefix)
for _, fldVal := range flt.Values {
if engine.IsDynamicDPPath(fldVal) {
continue
}
if isDyn {
if !strings.HasPrefix(fldVal, utils.DynamicDataPrefix) {
indxIDs = append(indxIDs, utils.ConcatenatedKey(flt.Type, flt.Element[1:], fldVal))
}
} else if strings.HasPrefix(fldVal, utils.DynamicDataPrefix) {
indxIDs = append(indxIDs, utils.ConcatenatedKey(flt.Type, fldVal[1:], flt.Element))
}
}
}
if len(indxIDs) == 0 { // no index
return args, nil
}
var rcvIndx map[string]utils.StringSet
if rcvIndx, err = dm.GetIndexes(ctx, utils.CacheReverseFilterIndexes, tntID,
utils.EmptyString, utils.EmptyString, true, true); err != nil && err != utils.ErrNotFound { // error when geting the revers
return
}
if err == utils.ErrNotFound || len(rcvIndx) == 0 { // no reverse index for this filter
return args, nil
}
for k := range rcvIndx {
for _, indx := range indxIDs {
args[k] = append(args[k], utils.ConcatenatedKey(tnt, indx))
}
}
return args, nil
}
// callCacheForFilter will call the cache for filter
func callCacheForFilter(connMgr *engine.ConnManager, cacheConns []string, ctx *context.Context, cacheopt, dftCache, tnt string,
argC map[string][]string, opts map[string]any) (err error) {
var reply, method string
var args any = utils.NewAttrReloadCacheWithOptsFromMap(argC, tnt, opts)
switch utils.FirstNonEmpty(cacheopt, dftCache) {
case utils.MetaNone:
return
case utils.MetaReload:
method = utils.CacheSv1ReloadCache
case utils.MetaLoad:
method = utils.CacheSv1LoadCache
case utils.MetaRemove:
method = utils.CacheSv1RemoveItems
case utils.MetaClear:
cacheIDs := make([]string, 0, len(argC))
for k := range argC {
cacheIDs = append(cacheIDs, k)
}
method = utils.CacheSv1Clear
args = &utils.AttrCacheIDsWithAPIOpts{
Tenant: tnt,
CacheIDs: cacheIDs,
APIOpts: opts,
}
}
return connMgr.Call(ctx, cacheConns, method, args, &reply)
}

292
admins/rates.go Normal file
View File

@@ -0,0 +1,292 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"sort"
"strings"
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/utils"
)
// GetRateProfile returns a Rate Profile based on tenant and id
func (admS *AdminS) V1GetRateProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *utils.RateProfile) (err 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 = admS.cfg.GeneralCfg().DefaultTenant
}
var rPrf *utils.RateProfile
rPrf, err = admS.dm.GetRateProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
if err != nil {
if err.Error() != utils.ErrNotFound.Error() {
err = utils.NewErrServerError(err)
}
return
}
rateIDs := make([]string, 0, len(rPrf.Rates))
prefix := utils.IfaceAsString(arg.APIOpts[utils.ItemsPrefixOpt])
for rateID := range rPrf.Rates {
if strings.HasPrefix(rateID, prefix) {
rateIDs = append(rateIDs, rateID)
}
}
sort.Strings(rateIDs)
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(arg.APIOpts); err != nil {
return
}
rateIDs, err = utils.Paginate(rateIDs, limit, offset, maxItems)
if err != nil {
return
}
paginatedRatePrf := &utils.RateProfile{
Tenant: rPrf.Tenant,
ID: rPrf.ID,
FilterIDs: rPrf.FilterIDs,
Weights: rPrf.Weights,
MinCost: rPrf.MinCost,
MaxCost: rPrf.MaxCost,
MaxCostStrategy: rPrf.MaxCostStrategy,
}
paginatedRatePrf.Rates = make(map[string]*utils.Rate)
for _, rateID := range rateIDs {
paginatedRatePrf.Rates[rateID] = rPrf.Rates[rateID].Clone()
}
*reply = *paginatedRatePrf
return
}
// GetRateProfile returns the rates of a profile based on their profile. Those rates will be returned back by matching a prefix.
func (admS *AdminS) V1GetRateProfileRates(ctx *context.Context, args *utils.ArgsSubItemIDs, reply *[]*utils.Rate) (err error) {
if missing := utils.MissingStructFields(args, []string{utils.ProfileID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
_, rates, err := admS.dm.GetRateProfileRates(ctx, args, false)
if err != nil {
return
}
if len(rates) == 0 {
return utils.ErrNotFound
}
*reply = rates
return
}
// GetRateProfileIDs returns a list of rate profile IDs registered for a tenant
func (admS *AdminS) V1GetRateProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, ratePrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.RateProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*ratePrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetRateProfileRateIDs returns a list of rates from a specific RateProfile registered for a tenant. RateIDs are returned back by matching a pattern given by ItemPrefix. If the ItemPrefix is not there, it will be returned all RateIDs.
func (admS *AdminS) V1GetRateProfileRateIDs(ctx *context.Context, args *utils.ArgsSubItemIDs, rateIDs *[]string) (err error) {
if missing := utils.MissingStructFields(args, []string{utils.ProfileID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
var ids []string
ids, _, err = admS.dm.GetRateProfileRates(ctx, args, true)
if err != nil {
return
}
if len(ids) == 0 {
return utils.ErrNotFound
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*rateIDs, err = utils.Paginate(ids, limit, offset, maxItems)
return
}
// GetRateProfiles returns a list of rate profiles registered for a tenant
func (admS *AdminS) V1GetRateProfiles(ctx *context.Context, args *utils.ArgsItemIDs, ratePrfs *[]*utils.RateProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var ratePrfIDs []string
if err = admS.V1GetRateProfileIDs(ctx, args, &ratePrfIDs); err != nil {
return
}
*ratePrfs = make([]*utils.RateProfile, 0, len(ratePrfIDs))
for _, ratePrfID := range ratePrfIDs {
var ratePrf *utils.RateProfile
ratePrf, err = admS.dm.GetRateProfile(ctx, tnt, ratePrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*ratePrfs = append(*ratePrfs, ratePrf)
}
return
}
// GetRateProfilesCount returns the total number of RateProfileIDs registered for a tenant
// returns ErrNotFound in case of 0 RateProfileIDs
func (admS *AdminS) V1GetRateProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.RateProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// GetRateProfileRatesCount count the rates from a specific RateProfile registered for a tenant. The number of rates is returned back by matching a pattern given by ItemPrefix. If the ItemPrefix is not there, it will be counted all the rates.
func (admS *AdminS) V1GetRateProfileRatesCount(ctx *context.Context, args *utils.ArgsSubItemIDs, countIDs *int) (err error) {
if missing := utils.MissingStructFields(args, []string{utils.ProfileID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
var ids []string
ids, _, err = admS.dm.GetRateProfileRates(ctx, args, true)
if err != nil {
return
}
if len(ids) == 0 {
return utils.ErrNotFound
}
*countIDs = len(ids)
return
}
// SetRateProfile add/update a new Rate Profile
func (admS *AdminS) V1SetRateProfile(ctx *context.Context, args *utils.APIRateProfile, reply *string) (err error) {
if missing := utils.MissingStructFields(args, []string{utils.ID, utils.Rates}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = admS.cfg.GeneralCfg().DefaultTenant
}
// check if we want to overwrite our profile already existing in database
var optOverwrite bool
if _, has := args.APIOpts[utils.MetaRateSOverwrite]; has {
optOverwrite, err = utils.IfaceAsBool(args.APIOpts[utils.MetaRateSOverwrite])
if err != nil {
return
}
}
if err := admS.dm.SetRateProfile(ctx, args.RateProfile, optOverwrite, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheRateProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), args.Tenant, utils.CacheRateProfiles,
args.TenantID(), utils.EmptyString, &args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveRateProfileRates removes the rates from the Rate Profile
func (admS *AdminS) V1RemoveRateProfileRates(ctx *context.Context, args *utils.RemoveRPrfRates, reply *string) (err error) {
if missing := utils.MissingStructFields(args, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveRateProfileRates(ctx, tnt, args.ID, &args.RateIDs, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheRateProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), tnt, utils.CacheRateProfiles,
utils.ConcatenatedKey(tnt, args.ID), utils.EmptyString, nil, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveRateProfile remove a specific Rate Profile specified by tenant and id
func (admS *AdminS) V1RemoveRateProfile(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 = admS.cfg.GeneralCfg().DefaultTenant
}
if err := admS.dm.RemoveRateProfile(ctx, tnt, arg.ID,
true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheAttributeProfiles and store it in database
if err := admS.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheRateProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
if err := admS.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheRateProfiles,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

168
admins/resources.go Normal file
View File

@@ -0,0 +1,168 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetResourceProfile returns a resource configuration
func (adms *AdminS) V1GetResourceProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.ResourceProfile) 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 = adms.cfg.GeneralCfg().DefaultTenant
}
if rcfg, err := adms.dm.GetResourceProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
} else {
*reply = *rcfg
}
return nil
}
// GetResourceProfileIDs returns list of resourceProfile IDs registered for a tenant
func (adms *AdminS) V1GetResourceProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, rsPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ResourceProfilesPrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*rsPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetResourceProfiles returns a list of resource profiles registered for a tenant
func (admS *AdminS) V1GetResourceProfiles(ctx *context.Context, args *utils.ArgsItemIDs, rsPrfs *[]*engine.ResourceProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var rsPrfIDs []string
if err = admS.V1GetResourceProfileIDs(ctx, args, &rsPrfIDs); err != nil {
return
}
*rsPrfs = make([]*engine.ResourceProfile, 0, len(rsPrfIDs))
for _, rsPrfID := range rsPrfIDs {
var rsPrf *engine.ResourceProfile
rsPrf, err = admS.dm.GetResourceProfile(ctx, tnt, rsPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*rsPrfs = append(*rsPrfs, rsPrf)
}
return
}
// GetResourceProfilesCount returns the total number of ResourceProfileIDs registered for a tenant
// returns ErrNotFound in case of 0 ResourceProfileIDs
func (admS *AdminS) V1GetResourceProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ResourceProfilesPrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetResourceProfile adds a new resource configuration
func (adms *AdminS) V1SetResourceProfile(ctx *context.Context, arg *engine.ResourceProfileWithAPIOpts, reply *string) (err error) {
if missing := utils.MissingStructFields(arg.ResourceProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if arg.Tenant == utils.EmptyString {
arg.Tenant = adms.cfg.GeneralCfg().DefaultTenant
}
if err = adms.dm.SetResourceProfile(ctx, arg.ResourceProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheResourceProfiles and CacheResources and store it in database
//make 1 insert for both ResourceProfile and Resources instead of 2
loadID := time.Now().UnixNano()
if err = adms.dm.SetLoadIDs(ctx,
map[string]int64{utils.CacheResourceProfiles: loadID,
utils.CacheResources: loadID}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for ResourceProfile
if err = adms.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), arg.Tenant, utils.CacheResourceProfiles,
arg.TenantID(), utils.EmptyString, &arg.FilterIDs, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveResourceProfile remove a specific resource configuration
func (adms *AdminS) V1RemoveResourceProfile(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 = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.RemoveResourceProfile(ctx, tnt, arg.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for ResourceProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), tnt, utils.CacheResourceProfiles,
utils.ConcatenatedKey(tnt, arg.ID), utils.EmptyString, nil, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheResourceProfiles and CacheResources and store it in database
//make 1 insert for both ResourceProfile and Resources instead of 2
loadID := time.Now().UnixNano()
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheResourceProfiles: loadID, utils.CacheResources: loadID}); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

165
admins/routes.go Normal file
View File

@@ -0,0 +1,165 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetRouteProfile returns a Route configuration
func (adms *AdminS) V1GetRouteProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.RouteProfile) 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 = adms.cfg.GeneralCfg().DefaultTenant
}
if rp, err := adms.dm.GetRouteProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional); err != nil {
return utils.APIErrorHandler(err)
} else {
*reply = *rp
}
return nil
}
// GetRouteProfileIDs returns list of routeProfile IDs registered for a tenant
func (adms *AdminS) V1GetRouteProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, routeProfileIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.RouteProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*routeProfileIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetRouteProfiles returns a list of route profiles registered for a tenant
func (admS *AdminS) V1GetRouteProfiles(ctx *context.Context, args *utils.ArgsItemIDs, rouPrfs *[]*engine.RouteProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var rouPrfIDs []string
if err = admS.V1GetRouteProfileIDs(ctx, args, &rouPrfIDs); err != nil {
return
}
*rouPrfs = make([]*engine.RouteProfile, 0, len(rouPrfIDs))
for _, rouPrfID := range rouPrfIDs {
var rouPrf *engine.RouteProfile
rouPrf, err = admS.dm.GetRouteProfile(ctx, tnt, rouPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*rouPrfs = append(*rouPrfs, rouPrf)
}
return
}
// GetRouteProfilesCount sets in reply var the total number of RouteProfileIDs registered for the received tenant
// returns ErrNotFound in case of 0 RouteProfileIDs
func (adms *AdminS) V1GetRouteProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.RouteProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetRouteProfile add a new Route configuration
func (adms *AdminS) V1SetRouteProfile(ctx *context.Context, args *engine.RouteProfileWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.RouteProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = adms.cfg.GeneralCfg().DefaultTenant
}
if len(args.Routes) == 0 {
return utils.NewErrMandatoryIeMissing("Routes")
}
if err := adms.dm.SetRouteProfile(ctx, args.RouteProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheRouteProfiles and store it in database
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheRouteProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for SupplierProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), args.Tenant, utils.CacheRouteProfiles,
args.TenantID(), utils.EmptyString, &args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveRouteProfile remove a specific Route configuration
func (adms *AdminS) V1RemoveRouteProfile(ctx *context.Context, args *utils.TenantIDWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args, []string{utils.ID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.RemoveRouteProfile(ctx, tnt, args.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheRouteProfiles and store it in database
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheRouteProfiles: time.Now().UnixNano()}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for SupplierProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), tnt, utils.CacheRouteProfiles,
utils.ConcatenatedKey(tnt, args.ID), utils.EmptyString, nil, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

166
admins/stats.go Normal file
View File

@@ -0,0 +1,166 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetStatQueueProfile returns a StatQueue profile
func (adms *AdminS) V1GetStatQueueProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.StatQueueProfile) (err 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 = adms.cfg.GeneralCfg().DefaultTenant
}
sCfg, err := adms.dm.GetStatQueueProfile(ctx, tnt, arg.ID,
true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*reply = *sCfg
return
}
// GetStatQueueProfileIDs returns list of statQueueProfile IDs registered for a tenant
func (adms *AdminS) V1GetStatQueueProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, stsPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.StatQueueProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*stsPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetStatQueueProfiles returns a list of stats profiles registered for a tenant
func (admS *AdminS) V1GetStatQueueProfiles(ctx *context.Context, args *utils.ArgsItemIDs, sqPrfs *[]*engine.StatQueueProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var sqPrfIDs []string
if err = admS.V1GetStatQueueProfileIDs(ctx, args, &sqPrfIDs); err != nil {
return
}
*sqPrfs = make([]*engine.StatQueueProfile, 0, len(sqPrfIDs))
for _, sqPrfID := range sqPrfIDs {
var sqPrf *engine.StatQueueProfile
sqPrf, err = admS.dm.GetStatQueueProfile(ctx, tnt, sqPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*sqPrfs = append(*sqPrfs, sqPrf)
}
return
}
// GetStatQueueProfilesCount returns the total number of StatQueueProfileIDs registered for a tenant
// returns ErrNotFound in case of 0 StatQueueProfileIDs
func (admS *AdminS) V1GetStatQueueProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.StatQueueProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = admS.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetStatQueueProfile alters/creates a StatQueueProfile
func (adms *AdminS) V1SetStatQueueProfile(ctx *context.Context, arg *engine.StatQueueProfileWithAPIOpts, reply *string) (err error) {
if missing := utils.MissingStructFields(arg.StatQueueProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if arg.Tenant == utils.EmptyString {
arg.Tenant = adms.cfg.GeneralCfg().DefaultTenant
}
if err = adms.dm.SetStatQueueProfile(ctx, arg.StatQueueProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheStatQueueProfiles and CacheStatQueues and store it in database
//make 1 insert for both StatQueueProfile and StatQueue instead of 2
loadID := time.Now().UnixNano()
if err = adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheStatQueueProfiles: loadID, utils.CacheStatQueues: loadID}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for StatQueueProfile
if err = adms.CallCache(ctx, utils.IfaceAsString(arg.APIOpts[utils.MetaCache]), arg.Tenant, utils.CacheStatQueueProfiles,
arg.TenantID(), utils.EmptyString, &arg.FilterIDs, arg.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveStatQueueProfile remove a specific stat configuration
func (adms *AdminS) V1RemoveStatQueueProfile(ctx *context.Context, args *utils.TenantIDWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args, []string{utils.ID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.RemoveStatQueueProfile(ctx, tnt, args.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for StatQueueProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), tnt, utils.CacheStatQueueProfiles,
utils.ConcatenatedKey(tnt, args.ID), utils.EmptyString, nil, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheStatQueueProfiles and CacheStatQueues and store it in database
//make 1 insert for both StatQueueProfile and StatQueue instead of 2
loadID := time.Now().UnixNano()
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheStatQueueProfiles: loadID, utils.CacheStatQueues: loadID}); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}

166
admins/thresholds.go Normal file
View File

@@ -0,0 +1,166 @@
/*
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 <http://www.gnu.org/licenses/>
*/
package admins
import (
"time"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
)
// GetThresholdProfile returns a Threshold Profile
func (adms *AdminS) V1GetThresholdProfile(ctx *context.Context, arg *utils.TenantIDWithAPIOpts, reply *engine.ThresholdProfile) (err 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 = adms.cfg.GeneralCfg().DefaultTenant
}
th, err := adms.dm.GetThresholdProfile(ctx, tnt, arg.ID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*reply = *th
return
}
// GetThresholdProfileIDs returns list of thresholdProfile IDs registered for a tenant
func (adms *AdminS) V1GetThresholdProfileIDs(ctx *context.Context, args *utils.ArgsItemIDs, thPrfIDs *[]string) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ThresholdProfilePrefix + tnt + utils.ConcatenatedKeySep
lenPrfx := len(prfx)
prfx += args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return
}
if len(keys) == 0 {
return utils.ErrNotFound
}
retIDs := make([]string, len(keys))
for i, key := range keys {
retIDs[i] = key[lenPrfx:]
}
var limit, offset, maxItems int
if limit, offset, maxItems, err = utils.GetPaginateOpts(args.APIOpts); err != nil {
return
}
*thPrfIDs, err = utils.Paginate(retIDs, limit, offset, maxItems)
return
}
// GetThresholdProfiles returns a list of threshold profiles registered for a tenant
func (admS *AdminS) V1GetThresholdProfiles(ctx *context.Context, args *utils.ArgsItemIDs, thdPrfs *[]*engine.ThresholdProfile) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = admS.cfg.GeneralCfg().DefaultTenant
}
var thdPrfIDs []string
if err = admS.V1GetThresholdProfileIDs(ctx, args, &thdPrfIDs); err != nil {
return
}
*thdPrfs = make([]*engine.ThresholdProfile, 0, len(thdPrfIDs))
for _, thdPrfID := range thdPrfIDs {
var thdPrf *engine.ThresholdProfile
thdPrf, err = admS.dm.GetThresholdProfile(ctx, tnt, thdPrfID, true, true, utils.NonTransactional)
if err != nil {
return utils.APIErrorHandler(err)
}
*thdPrfs = append(*thdPrfs, thdPrf)
}
return
}
// GetThresholdProfilesCount sets in reply var the total number of ThresholdProfileIDs registered for the received tenant
// returns ErrNotFound in case of 0 ThresholdProfileIDs
func (adms *AdminS) V1GetThresholdProfilesCount(ctx *context.Context, args *utils.ArgsItemIDs, reply *int) (err error) {
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
prfx := utils.ThresholdProfilePrefix + tnt + utils.ConcatenatedKeySep + args.ItemsPrefix
var keys []string
if keys, err = adms.dm.DataDB().GetKeysForPrefix(ctx, prfx); err != nil {
return err
}
if len(keys) == 0 {
return utils.ErrNotFound
}
*reply = len(keys)
return
}
// SetThresholdProfile alters/creates a ThresholdProfile
func (adms *AdminS) V1SetThresholdProfile(ctx *context.Context, args *engine.ThresholdProfileWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args.ThresholdProfile, []string{utils.ID}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
if args.Tenant == utils.EmptyString {
args.Tenant = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.SetThresholdProfile(ctx, args.ThresholdProfile, true); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheThresholdProfiles and CacheThresholds and store it in database
//make 1 insert for both ThresholdProfile and Threshold instead of 2
loadID := time.Now().UnixNano()
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheThresholdProfiles: loadID, utils.CacheThresholds: loadID}); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for ThresholdProfile and Threshold
if err := adms.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), args.Tenant, utils.CacheThresholdProfiles,
args.TenantID(), utils.EmptyString, &args.FilterIDs, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}
// RemoveThresholdProfile removes a specific Threshold Profile
func (adms *AdminS) V1RemoveThresholdProfile(ctx *context.Context, args *utils.TenantIDWithAPIOpts, reply *string) error {
if missing := utils.MissingStructFields(args, []string{utils.ID}); len(missing) != 0 { //Params missing
return utils.NewErrMandatoryIeMissing(missing...)
}
tnt := args.Tenant
if tnt == utils.EmptyString {
tnt = adms.cfg.GeneralCfg().DefaultTenant
}
if err := adms.dm.RemoveThresholdProfile(ctx, tnt, args.ID, true); err != nil {
return utils.APIErrorHandler(err)
}
//handle caching for ThresholdProfile
if err := adms.CallCache(ctx, utils.IfaceAsString(args.APIOpts[utils.MetaCache]), tnt, utils.CacheThresholdProfiles,
utils.ConcatenatedKey(tnt, args.ID), utils.EmptyString, nil, args.APIOpts); err != nil {
return utils.APIErrorHandler(err)
}
//generate a loadID for CacheThresholdProfiles and CacheThresholds and store it in database
//make 1 insert for both ThresholdProfile and Threshold instead of 2
loadID := time.Now().UnixNano()
if err := adms.dm.SetLoadIDs(ctx, map[string]int64{utils.CacheThresholdProfiles: loadID, utils.CacheThresholds: loadID}); err != nil {
return utils.APIErrorHandler(err)
}
*reply = utils.OK
return nil
}