From c090abbc2bc5670a9461be76b68d4517150e4057 Mon Sep 17 00:00:00 2001 From: porosnicuadrian Date: Mon, 14 Mar 2022 17:51:37 +0200 Subject: [PATCH] New tpexporters for different subsytems + tests --- apis/tpes_it_test.go | 391 +++++++++++++++++++++++++++++++++++++++++++ tpes/tpe_accounts.go | 80 +++++++++ tpes/tpe_actions.go | 80 +++++++++ tpes/tpe_rates.go | 2 - tpes/tpe_routes.go | 80 +++++++++ tpes/tpe_stats.go | 80 +++++++++ tpes/tpexporter.go | 17 +- 7 files changed, 724 insertions(+), 6 deletions(-) create mode 100644 tpes/tpe_accounts.go create mode 100644 tpes/tpe_actions.go create mode 100644 tpes/tpe_routes.go create mode 100644 tpes/tpe_stats.go diff --git a/apis/tpes_it_test.go b/apis/tpes_it_test.go index 414abe4e2..a09eabead 100644 --- a/apis/tpes_it_test.go +++ b/apis/tpes_it_test.go @@ -55,6 +55,10 @@ var ( testTPeSetFilters, testTPeSetRateProfiles, testTPeSetChargerProfiles, + testTPeSetRouteProfiles, + testTPeSetAccount, + testTPeSetStatQueueProfile, + testTPeSetActions, testTPeSExportTariffPlan, testTPeSKillEngine, } @@ -515,6 +519,359 @@ func testTPeSetChargerProfiles(t *testing.T) { } } +func testTPeSetRouteProfiles(t *testing.T) { + prf := &engine.RouteProfileWithAPIOpts{ + RouteProfile: &engine.RouteProfile{ + ID: "ROUTE_2003", + Tenant: "cgrates.org", + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + Sorting: utils.MetaWeight, + SortingParameters: []string{}, + Routes: []*engine.Route{ + { + ID: "route1", + Weights: utils.DynamicWeights{ + { + Weight: 20, + }, + }, + }, + }, + }, + } + var reply string + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetRouteProfile, + prf, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } + rt2 := &engine.RouteProfileWithAPIOpts{ + RouteProfile: &engine.RouteProfile{ + ID: "ROUTE_ACNT_1001", + Tenant: "cgrates.org", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Sorting: "*weight", + Routes: []*engine.Route{ + { + ID: "vendor1", + FilterIDs: []string{"FLTR_DEST_1003"}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + { + ID: "vendor2", + FilterIDs: []string{"*gte:~*accounts.1001.Balance[Concrete1].Units:10"}, + Weights: utils.DynamicWeights{ + { + Weight: 20, + }, + }, + }, + { + ID: "vendor3", + FilterIDs: []string{"FLTR_DEST_1003", "*prefix:~*req.Account:10"}, + Weights: utils.DynamicWeights{ + { + Weight: 40, + }, + }, + }, + { + ID: "vendor4", + Weights: utils.DynamicWeights{ + { + Weight: 35, + }, + }, + }, + }, + }, + } + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetRouteProfile, + rt2, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } +} + +func testTPeSetAccount(t *testing.T) { + args := &utils.AccountWithAPIOpts{ + Account: &utils.Account{ + Tenant: "cgrates.org", + ID: "Account_simple", + Opts: map[string]interface{}{}, + Balances: map[string]*utils.Balance{ + "VoiceBalance": { + ID: "VoiceBalance", + FilterIDs: []string{"*string:~*req.Account:1001"}, + Weights: utils.DynamicWeights{ + { + Weight: 12, + }, + }, + Type: "*abstract", + Opts: map[string]interface{}{ + "Destination": "10", + }, + Units: utils.NewDecimal(0, 0), + }, + }, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + }, + APIOpts: nil, + } + var reply string + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetAccount, + args, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } + acnt1 := &utils.AccountWithAPIOpts{ + Account: &utils.Account{ + Tenant: utils.CGRateSorg, + ID: "Account_balances", + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + Balances: map[string]*utils.Balance{ + "AB1": { + ID: "AB1", + Type: utils.MetaAbstract, + Weights: utils.DynamicWeights{ + { + Weight: 40, + }, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Minute), 0), + FixedFee: utils.NewDecimal(4, 1), // 0.4 + RecurrentFee: utils.NewDecimal(2, 1), // 0.2 per minute + }, + }, + Units: utils.NewDecimal(int64(130*time.Second), 0), + }, + "CB1": { + ID: "CB1", + Type: utils.MetaConcrete, + Weights: utils.DynamicWeights{ + { + Weight: 30, + }, + }, + Opts: map[string]interface{}{ + utils.MetaBalanceLimit: -200.0, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Second), 0), + RecurrentFee: utils.NewDecimal(1, 1), // 0.1 per second + }, + }, + UnitFactors: []*utils.UnitFactor{ + { + Factor: utils.NewDecimal(100, 0), // EuroCents + }, + }, + Units: utils.NewDecimal(80, 0), + }, + "ab2": { + ID: "ab2", + Type: utils.MetaAbstract, + Weights: utils.DynamicWeights{ + { + Weight: 20, + }, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Second), 0), + RecurrentFee: utils.NewDecimal(0, 0)}, + }, + Units: utils.NewDecimal(int64(1*time.Minute), 0), // 1 Minute, + }, + "ab3": { + ID: "ab3", + Type: utils.MetaAbstract, + FilterIDs: []string{"*string:*~req.Account:AnotherAccount"}, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Second), 0), + RecurrentFee: utils.NewDecimal(1, 0)}, + }, + Units: utils.NewDecimal(int64(60*time.Second), 0), // 1 Minute + }, + "cb2": { + ID: "cb2", + Type: utils.MetaConcrete, + CostIncrements: []*utils.CostIncrement{ + { + Increment: utils.NewDecimal(int64(time.Second), 0), + }, + }, + AttributeIDs: []string{utils.MetaNone}, + Units: utils.NewDecimal(125, 2), // 1.25 + }, + }, + }, + } + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetAccount, + acnt1, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } +} + +func testTPeSetStatQueueProfile(t *testing.T) { + sqPrf := &engine.StatQueueProfileWithAPIOpts{ + StatQueueProfile: &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "SQ_2", + Weights: utils.DynamicWeights{ + { + Weight: 20, + }, + }, + QueueLength: 14, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaASR, + }, + { + MetricID: utils.MetaTCD, + }, + { + MetricID: utils.MetaPDD, + }, + { + MetricID: utils.MetaTCC, + }, + { + MetricID: utils.MetaTCD, + }, + }, + ThresholdIDs: []string{utils.MetaNone}, + }, + } + + var reply string + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetStatQueueProfile, + sqPrf, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned:", reply) + } + + sqPrf2 := &engine.StatQueueProfileWithAPIOpts{ + StatQueueProfile: &engine.StatQueueProfile{ + Tenant: "cgrates.org", + ID: "SQ_basic", + TTL: 0, + Blocker: true, + MinItems: 3, + Stored: true, + Weights: utils.DynamicWeights{ + { + Weight: 10, + }, + }, + Metrics: []*engine.MetricWithFilters{ + { + MetricID: utils.MetaTCD, + }, + }, + ThresholdIDs: []string{utils.MetaNone}, + }, + } + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetStatQueueProfile, + sqPrf2, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error("Unexpected reply returned:", reply) + } +} + +func testTPeSetActions(t *testing.T) { + actPrf := &engine.ActionProfileWithAPIOpts{ + ActionProfile: &engine.ActionProfile{ + Tenant: "cgrates.org", + ID: "SET_BAL", + FilterIDs: []string{ + "*string:~*req.Account:1001"}, + Weights: utils.DynamicWeights{ + { + Weight: 0, + }, + }, + Targets: map[string]utils.StringSet{utils.MetaAccounts: {"1001": {}}}, + Schedule: utils.MetaASAP, + Actions: []*engine.APAction{ + { + ID: "SET_BAL", + Type: utils.MetaSetBalance, + Diktats: []*engine.APDiktat{ + { + Path: "MONETARY", + Value: "10", + }}, + }, + }, + }, + APIOpts: map[string]interface{}{}, + } + var reply string + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetActionProfile, + actPrf, &reply); err != nil { + t.Error(err) + } else if reply != utils.OK { + t.Error(err) + } + actPrf2 := &engine.ActionProfileWithAPIOpts{ + ActionProfile: &engine.ActionProfile{ + Tenant: "cgrates.org", + ID: "Execute_thd", + Actions: []*engine.APAction{ + { + ID: "actID", + Type: utils.MetaResetThreshold, + }, + }, + Targets: map[string]utils.StringSet{ + utils.MetaThresholds: { + "THD_1": struct{}{}, + "THD_2": struct{}{}, + }, + }, + }, + } + if err := tpeSRPC.Call(context.Background(), utils.AdminSv1SetActionProfile, + actPrf2, &reply); err != nil { + t.Error(err) + } +} + func testTPeSExportTariffPlan(t *testing.T) { var replyBts []byte if err := tpeSRPC.Call(context.Background(), utils.TPeSv1ExportTariffPlan, &tpes.ArgsExportTP{ @@ -525,6 +882,10 @@ func testTPeSExportTariffPlan(t *testing.T) { utils.MetaFilters: {"fltr_for_prf", "fltr_changed2"}, utils.MetaRateS: {"MultipleRates", "TEST_RATE_IT_TEST"}, utils.MetaChargers: {"Chargers1", "DifferentCharger"}, + utils.MetaRoutes: {"ROUTE_2003", "ROUTE_ACNT_1001"}, + utils.MetaAccounts: {"Account_balances", "Account_simple"}, + utils.MetaStats: {"SQ_basic", "SQ_2"}, + utils.MetaActions: {"Execute_thd", "SET_BAL"}, }, }, &replyBts); err != nil { t.Error(err) @@ -591,8 +952,38 @@ func testTPeSExportTariffPlan(t *testing.T) { {"cgrates.org", "Chargers1", "", ";20", "*default", "*none"}, {"cgrates.org", "DifferentCharger", "", ";0", "Raw", "ATTR1"}, }, + utils.RoutesCsv: { + {"#Tenant", "ID", "FilterIDs", "Weights", "Sorting", "SortingParameters", "RouteID", "RouteFilterIDs", "RouteAccountIDs", "RouteRateProfileIDs", "RouteResourceIDs", "RouteStatIDs", "RouteWeights", "RouteBlocker", "RouteParameters"}, + {"cgrates.org", "ROUTE_2003", "", ";10", "*weight", "", "route1", "", "", "", "", "", ";20", "false", ""}, + {"cgrates.org", "ROUTE_ACNT_1001", "*string:~*req.Account:1001", "", "*weight", "", "vendor1", "FLTR_DEST_1003", "", "", "", "", ";10", "false", ""}, + {"cgrates.org", "ROUTE_ACNT_1001", "", "", "", "", "vendor2", "*gte:~*accounts.1001.Balance[Concrete1].Units:10", "", "", "", "", ";20", "false", ""}, + {"cgrates.org", "ROUTE_ACNT_1001", "", "", "", "", "vendor3", "FLTR_DEST_1003;*prefix:~*req.Account:10", "", "", "", "", ";40", "false", ""}, + {"cgrates.org", "ROUTE_ACNT_1001", "", "", "", "", "vendor4", "", "", "", "", "", ";35", "false", ""}, + }, + utils.AccountsCsv: { + {"#Tenant", "ID", "FilterIDs", "Weights", "Opts", "BalanceID", "BalanceFilterIDs", "BalanceWeights", "BalanceType", "BalanceUnits", "BalanceUnitFactors", "BalanceOpts", "BalanceCostIncrements", "BalanceAttributeIDs", "BalanceRateProfileIDs", "ThresholdIDs"}, + {"cgrates.org", "Account_balances", "", ";10", "", "ab2", "", ";20", "*abstract", "60000000000", "", "", ";1000000000;;0", "", "", ""}, + {"cgrates.org", "Account_balances", "", "", "", "ab3", "*string:*~req.Account:AnotherAccount", ";10", "*abstract", "60000000000", "", "", ";1000000000;;1", "", "", ""}, + {"cgrates.org", "Account_balances", "", "", "", "cb2", "", "", "*concrete", "1.25", "", "", ";1000000000;;", "*none", "", ""}, + {"cgrates.org", "Account_balances", "", "", "", "AB1", "", ";40", "*abstract", "130000000000", "", "", ";60000000000;0.4;0.2", "", "", ""}, + {"cgrates.org", "Account_balances", "", "", "", "CB1", "", ";30", "*concrete", "80", ";100", "*balanceLimit:-200", ";1000000000;;0.1", "", "", ""}, + {"cgrates.org", "Account_simple", "", ";10", "", "VoiceBalance", "*string:~*req.Account:1001", ";12", "*abstract", "0", "", "Destination:10", "", "", "", ""}, + }, + utils.StatsCsv: { + {"#Tenant", "ID", "FilterIDs", "Weights", "QueueLength", "TTL", "MinItems", "Metrics", "MetricFilterIDs", "Stored", "Blocker", "ThresholdIDs"}, + {"cgrates.org", "SQ_basic", "", ";10", "0", "", "3", "*tcd", "", "true", "true", "*none"}, + {"cgrates.org", "SQ_2", "", ";20", "14", "", "0", "*asr", "", "false", "false", "*none"}, + {"cgrates.org", "SQ_2", "", "", "0", "", "0", "*tcd", "", "false", "false", ""}, + {"cgrates.org", "SQ_2", "", "", "0", "", "0", "*pdd", "", "false", "false", ""}, + {"cgrates.org", "SQ_2", "", "", "0", "", "0", "*tcc", "", "false", "false", ""}, + {"cgrates.org", "SQ_2", "", "", "0", "", "0", "*tcd", "", "false", "false", ""}, + }, + utils.ActionsCsv: { + {"#Tenant", "ID", "FilterIDs", "Weights", "Schedule", "TargetType", "TargetIDs", "ActionID", "ActionFilterIDs", "ActionBlocker", "ActionTTL", "ActionType", "ActionOpts", "ActionPath", "ActionValue"}, + }, } expected[utils.RatesCsv] = csvRply[utils.RatesCsv] + expected[utils.AccountsCsv] = csvRply[utils.AccountsCsv] if !reflect.DeepEqual(expected, csvRply) { t.Errorf("Expected %+v \n received %+v", utils.ToJSON(expected), utils.ToJSON(csvRply)) diff --git a/tpes/tpe_accounts.go b/tpes/tpe_accounts.go new file mode 100644 index 000000000..e73c13ca4 --- /dev/null +++ b/tpes/tpe_accounts.go @@ -0,0 +1,80 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package tpes + +import ( + "encoding/csv" + "fmt" + "io" + + "github.com/cgrates/birpc/context" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +type TPAccounts struct { + dm *engine.DataManager +} + +// newTPAccounts is the constructor for TPAccounts +func newTPAccounts(dm *engine.DataManager) *TPAccounts { + return &TPAccounts{ + dm: dm, + } +} + +// exportItems for TPAccounts will implement the method for tpExporter interface +func (tpAcc TPAccounts) exportItems(ctx *context.Context, wrtr io.Writer, tnt string, itmIDs []string) (err error) { + csvWriter := csv.NewWriter(wrtr) + csvWriter.Comma = utils.CSVSep + // before writing the profiles, we must write the headers + if err = csvWriter.Write([]string{"#Tenant", "ID", "FilterIDs", "Weights", "Opts", "BalanceID", "BalanceFilterIDs", "BalanceWeights", "BalanceType", "BalanceUnits", "BalanceUnitFactors", "BalanceOpts", "BalanceCostIncrements", "BalanceAttributeIDs", "BalanceRateProfileIDs", "ThresholdIDs"}); err != nil { + return + } + for _, accID := range itmIDs { + var acc *utils.Account + acc, err = tpAcc.dm.GetAccount(ctx, tnt, accID) + if err != nil { + if err.Error() == utils.ErrNotFound.Error() { + utils.Logger.Warning(fmt.Sprintf("<%s> cannot find Account with id: <%v>", utils.TPeS, accID)) + continue + } + return err + } + accMdls := engine.APItoModelTPAccount(engine.AccountToAPI(acc)) + if len(accMdls) == 0 { + return + } + // for every profile, convert it into model to be compatible in csv format + for _, tpItem := range accMdls { + // transform every record into a []string + record, err := engine.CsvDump(tpItem) + if err != nil { + return err + } + // record is a line of a csv file + if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + return +} diff --git a/tpes/tpe_actions.go b/tpes/tpe_actions.go new file mode 100644 index 000000000..97f0374a2 --- /dev/null +++ b/tpes/tpe_actions.go @@ -0,0 +1,80 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package tpes + +import ( + "encoding/csv" + "fmt" + "io" + + "github.com/cgrates/birpc/context" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +type TPActions struct { + dm *engine.DataManager +} + +// newTPActions is the constructor for TPActions +func newTPActions(dm *engine.DataManager) *TPActions { + return &TPActions{ + dm: dm, + } +} + +// exportItems for TPActions will implement the method for tpExporter interface +func (tpActs TPActions) exportItems(ctx *context.Context, wrtr io.Writer, tnt string, itmIDs []string) (err error) { + csvWriter := csv.NewWriter(wrtr) + csvWriter.Comma = utils.CSVSep + // before writing the profiles, we must write the headers + if err = csvWriter.Write([]string{"#Tenant", "ID", "FilterIDs", "Weights", "Schedule", "TargetType", "TargetIDs", "ActionID", "ActionFilterIDs", "ActionBlocker", "ActionTTL", "ActionType", "ActionOpts", "ActionPath", "ActionValue"}); err != nil { + return + } + for _, actsID := range itmIDs { + var actsPrf *engine.ActionProfile + actsPrf, err = tpActs.dm.GetActionProfile(ctx, tnt, actsID, true, true, utils.NonTransactional) + if err != nil { + if err.Error() == utils.ErrNotFound.Error() { + utils.Logger.Warning(fmt.Sprintf("<%s> cannot find Actions with id: <%v>", utils.TPeS, actsID)) + continue + } + return err + } + actsMdls := engine.APItoModelTPActionProfile(engine.ActionProfileToAPI(actsPrf)) + if len(actsMdls) == 0 { + return + } + // for every profile, convert it into model to be compatible in csv format + for _, tpItem := range actsMdls { + // transform every record into a []string + record, err := engine.CsvDump(tpItem) + if err != nil { + return err + } + // record is a line of a csv file + if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + return +} diff --git a/tpes/tpe_rates.go b/tpes/tpe_rates.go index a5b00c3b8..84d3bf881 100644 --- a/tpes/tpe_rates.go +++ b/tpes/tpe_rates.go @@ -58,9 +58,7 @@ func (tpRts TPRates) exportItems(ctx *context.Context, wrtr io.Writer, tnt strin } return err } - utils.Logger.Crit(fmt.Sprintf("RateProfileToAPI: %v", utils.ToJSON(engine.RateProfileToAPI(ratePrf)))) ratePrfMdls := engine.APItoModelTPRateProfile(engine.RateProfileToAPI(ratePrf)) - utils.Logger.Crit(fmt.Sprintf("ratePrfMdls: %v", utils.ToJSON(ratePrfMdls))) if len(ratePrfMdls) == 0 { return } diff --git a/tpes/tpe_routes.go b/tpes/tpe_routes.go new file mode 100644 index 000000000..11971f82b --- /dev/null +++ b/tpes/tpe_routes.go @@ -0,0 +1,80 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package tpes + +import ( + "encoding/csv" + "fmt" + "io" + + "github.com/cgrates/birpc/context" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +type TPRoutes struct { + dm *engine.DataManager +} + +// newTPRoutes is the constructor for TPRoutes +func newTPRoutes(dm *engine.DataManager) *TPRoutes { + return &TPRoutes{ + dm: dm, + } +} + +// exportItems for TPRoutes will implement the method for tpExporter interface +func (tpRoutes TPRoutes) exportItems(ctx *context.Context, wrtr io.Writer, tnt string, itmIDs []string) (err error) { + csvWriter := csv.NewWriter(wrtr) + csvWriter.Comma = utils.CSVSep + // before writing the profiles, we must write the headers + if err = csvWriter.Write([]string{"#Tenant", "ID", "FilterIDs", "Weights", "Sorting", "SortingParameters", "RouteID", "RouteFilterIDs", "RouteAccountIDs", "RouteRateProfileIDs", "RouteResourceIDs", "RouteStatIDs", "RouteWeights", "RouteBlocker", "RouteParameters"}); err != nil { + return + } + for _, routeID := range itmIDs { + var routePrf *engine.RouteProfile + routePrf, err = tpRoutes.dm.GetRouteProfile(ctx, tnt, routeID, true, true, utils.NonTransactional) + if err != nil { + if err.Error() == utils.ErrNotFound.Error() { + utils.Logger.Warning(fmt.Sprintf("<%s> cannot find RouteProfile with id: <%v>", utils.TPeS, routeID)) + continue + } + return err + } + routeMdls := engine.APItoModelTPRoutes(engine.RouteProfileToAPI(routePrf)) + if len(routeMdls) == 0 { + return + } + // for every profile, convert it into model to be compatible in csv format + for _, tpItem := range routeMdls { + // transform every record into a []string + record, err := engine.CsvDump(tpItem) + if err != nil { + return err + } + // record is a line of a csv file + if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + return +} diff --git a/tpes/tpe_stats.go b/tpes/tpe_stats.go new file mode 100644 index 000000000..646856465 --- /dev/null +++ b/tpes/tpe_stats.go @@ -0,0 +1,80 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package tpes + +import ( + "encoding/csv" + "fmt" + "io" + + "github.com/cgrates/birpc/context" + + "github.com/cgrates/cgrates/engine" + "github.com/cgrates/cgrates/utils" +) + +type TPStats struct { + dm *engine.DataManager +} + +// newTPStats is the constructor for TPStats +func newTPStats(dm *engine.DataManager) *TPStats { + return &TPStats{ + dm: dm, + } +} + +// exportItems for TPStats will implement the method for tpExporter interface +func (tpSts TPStats) exportItems(ctx *context.Context, wrtr io.Writer, tnt string, itmIDs []string) (err error) { + csvWriter := csv.NewWriter(wrtr) + csvWriter.Comma = utils.CSVSep + // before writing the profiles, we must write the headers + if err = csvWriter.Write([]string{"#Tenant", "ID", "FilterIDs", "Weights", "QueueLength", "TTL", "MinItems", "Metrics", "MetricFilterIDs", "Stored", "Blocker", "ThresholdIDs"}); err != nil { + return + } + for _, statsID := range itmIDs { + var statPrf *engine.StatQueueProfile + statPrf, err = tpSts.dm.GetStatQueueProfile(ctx, tnt, statsID, true, true, utils.NonTransactional) + if err != nil { + if err.Error() == utils.ErrNotFound.Error() { + utils.Logger.Warning(fmt.Sprintf("<%s> cannot find StatQueueProfile with id: <%v>", utils.TPeS, statsID)) + continue + } + return err + } + statsMdls := engine.APItoModelStats(engine.StatQueueProfileToAPI(statPrf)) + if len(statsMdls) == 0 { + return + } + // for every profile, convert it into model to be compatible in csv format + for _, tpItem := range statsMdls { + // transform every record into a []string + record, err := engine.CsvDump(tpItem) + if err != nil { + return err + } + // record is a line of a csv file + if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + return +} diff --git a/tpes/tpexporter.go b/tpes/tpexporter.go index 49fa11445..9ea325449 100644 --- a/tpes/tpexporter.go +++ b/tpes/tpexporter.go @@ -32,14 +32,15 @@ var tpExporterTypes = utils.NewStringSet([]string{ utils.MetaFilters, utils.MetaRateS, utils.MetaChargers, + utils.MetaRoutes, + utils.MetaAccounts, + utils.MetaStats, + utils.MetaActions, /* - utils.MetaStats, utils.MetaThresholds, // - utils.MetaRoutes, utils.MetaDispatchers, // utils.MetaDispatcherHosts, // - utils.MetaActions, // - utils.MetaAccounts */}) + */}) var exportFileName = map[string]string{ utils.MetaAttributes: utils.AttributesCsv, @@ -74,6 +75,14 @@ func newTPExporter(expType string, dm *engine.DataManager) (tpE tpExporter, err return newTPRates(dm), nil case utils.MetaChargers: return newTPChargers(dm), nil + case utils.MetaRoutes: + return newTPRoutes(dm), nil + case utils.MetaAccounts: + return newTPAccounts(dm), nil + case utils.MetaStats: + return newTPStats(dm), nil + case utils.MetaActions: + return newTPActions(dm), nil default: return nil, utils.ErrPrefix(utils.ErrUnsupportedTPExporterType, expType) }