From f1029faca045404ab3477bb28196caa7a77e43f9 Mon Sep 17 00:00:00 2001 From: TeoV Date: Wed, 4 Mar 2020 18:04:15 +0200 Subject: [PATCH] Implement export for other items --- apier/v1/apier.go | 201 +++++++++++++- engine/model_helpers.go | 224 ++++++++++++---- engine/model_helpers_test.go | 194 ++++++++++++++ utils/consts.go | 502 ++++++++++++++++++----------------- 4 files changed, 826 insertions(+), 295 deletions(-) diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 7e4709081..6aebcda94 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -440,6 +440,8 @@ func (apiv1 *APIerSv1) SetRatingProfile(attrs utils.AttrSetRatingProfile, reply if err := apiv1.DataManager.SetRatingProfile(rpfl, utils.NonTransactional); err != nil { return utils.NewErrServerError(err) } + //CacheReload + //generate a loadID for CacheRatingProfiles and store it in database if err := apiv1.DataManager.SetLoadIDs(map[string]int64{utils.CacheRatingProfiles: time.Now().UnixNano()}); err != nil { return utils.APIErrorHandler(err) @@ -1364,8 +1366,8 @@ func (apiv1 *APIerSv1) Ping(ign *utils.CGREvent, reply *string) error { func (apiV1 *APIerSv1) ExportToFolder(arg *utils.ArgExportToFolder, reply *string) error { // if items is empy we need to export all items if len(arg.Items) == 0 { - arg.Items = []string{utils.MetaAttributes, utils.MetaChargers, utils.MetaDispatchers, utils.MetaFilters, - utils.MetaResources, utils.MetaStats, utils.MetaSuppliers, utils.MetaThresholds} + arg.Items = []string{utils.MetaAttributes, utils.MetaChargers, utils.MetaDispatchers, utils.MetaDispatcherHosts, + utils.MetaFilters, utils.MetaResources, utils.MetaStats, utils.MetaSuppliers, utils.MetaThresholds} } for _, item := range arg.Items { switch item { @@ -1375,7 +1377,6 @@ func (apiV1 *APIerSv1) ExportToFolder(arg *utils.ArgExportToFolder, reply *strin if err != nil { return err } - // take the tenant + id from key if len(keys) == 0 { // if we don't find items we skip continue } @@ -1388,13 +1389,10 @@ func (apiV1 *APIerSv1) ExportToFolder(arg *utils.ArgExportToFolder, reply *strin csvWriter := csv.NewWriter(f) csvWriter.Comma = utils.CSV_SEP //write the header of the file - // #Tenant,ID,Contexts,FilterIDs,ActivationInterval,AttributeFilterIDs,Path,Type,Value,Blocker,Weight - if err := csvWriter.Write([]string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationInternal, - utils.AttributeFilterIDs, utils.Path, utils.Type, utils.Value, utils.Blocker, utils.Weight}); err != nil { + if err := csvWriter.Write(engine.TPAttributes{}.CSVHeader()); err != nil { return err } for _, key := range keys { - // take tntID from key tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) attPrf, err := apiV1.DataManager.GetAttributeProfile(tntID[0], tntID[1], true, false, utils.NonTransactional) @@ -1409,7 +1407,196 @@ func (apiV1 *APIerSv1) ExportToFolder(arg *utils.ArgExportToFolder, reply *strin return err } } + } + csvWriter.Flush() + case utils.MetaChargers: + prfx := utils.ChargerProfilePrefix + keys, err := apiV1.DataManager.DataDB().GetKeysForPrefix(prfx) + if err != nil { + return err + } + if len(keys) == 0 { // if we don't find items we skip + continue + } + f, err := os.Create(path.Join(arg.Path, utils.ChargersCsv)) + if err != nil { + return err + } + defer f.Close() + csvWriter := csv.NewWriter(f) + csvWriter.Comma = utils.CSV_SEP + //write the header of the file + if err := csvWriter.Write(engine.TPChargers{}.CSVHeader()); err != nil { + return err + } + for _, key := range keys { + tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) + chrPrf, err := apiV1.DataManager.GetChargerProfile(tntID[0], tntID[1], + true, false, utils.NonTransactional) + if err != nil { + return err + } + for _, model := range engine.APItoModelTPCharger( + engine.ChargerProfileToAPI(chrPrf)) { + if record, err := engine.CsvDump(model); err != nil { + return err + } else if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + case utils.MetaDispatchers: + prfx := utils.DispatcherProfilePrefix + keys, err := apiV1.DataManager.DataDB().GetKeysForPrefix(prfx) + if err != nil { + return err + } + if len(keys) == 0 { // if we don't find items we skip + continue + } + f, err := os.Create(path.Join(arg.Path, utils.DispatcherProfilesCsv)) + if err != nil { + return err + } + defer f.Close() + + csvWriter := csv.NewWriter(f) + csvWriter.Comma = utils.CSV_SEP + //write the header of the file + if err := csvWriter.Write(engine.TPDispatcherProfiles{}.CSVHeader()); err != nil { + return err + } + for _, key := range keys { + tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) + dpsPrf, err := apiV1.DataManager.GetDispatcherProfile(tntID[0], tntID[1], + true, false, utils.NonTransactional) + if err != nil { + return err + } + for _, model := range engine.APItoModelTPDispatcherProfile( + engine.DispatcherProfileToAPI(dpsPrf)) { + if record, err := engine.CsvDump(model); err != nil { + return err + } else if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + case utils.MetaDispatcherHosts: + prfx := utils.DispatcherHostPrefix + keys, err := apiV1.DataManager.DataDB().GetKeysForPrefix(prfx) + if err != nil { + return err + } + if len(keys) == 0 { // if we don't find items we skip + continue + } + f, err := os.Create(path.Join(arg.Path, utils.DispatcherHostsCsv)) + if err != nil { + return err + } + defer f.Close() + + csvWriter := csv.NewWriter(f) + csvWriter.Comma = utils.CSV_SEP + //write the header of the file + if err := csvWriter.Write(engine.TPDispatcherHosts{}.CSVHeader()); err != nil { + return err + } + for _, key := range keys { + tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) + dpsPrf, err := apiV1.DataManager.GetDispatcherHost(tntID[0], tntID[1], + true, false, utils.NonTransactional) + if err != nil { + return err + } + for _, model := range engine.APItoModelTPDispatcherHost( + engine.DispatcherHostToAPI(dpsPrf)) { + if record, err := engine.CsvDump(model); err != nil { + return err + } else if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + case utils.MetaFilters: + prfx := utils.FilterPrefix + keys, err := apiV1.DataManager.DataDB().GetKeysForPrefix(prfx) + if err != nil { + return err + } + if len(keys) == 0 { // if we don't find items we skip + continue + } + f, err := os.Create(path.Join(arg.Path, utils.FiltersCsv)) + if err != nil { + return err + } + defer f.Close() + + csvWriter := csv.NewWriter(f) + csvWriter.Comma = utils.CSV_SEP + //write the header of the file + if err := csvWriter.Write(engine.TpFilterS{}.CSVHeader()); err != nil { + return err + } + for _, key := range keys { + tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) + fltr, err := engine.GetFilter(apiV1.DataManager, tntID[0], tntID[1], + true, false, utils.NonTransactional) + if err != nil { + return err + } + for _, model := range engine.APItoModelTPFilter( + engine.FilterToTPFilter(fltr)) { + if record, err := engine.CsvDump(model); err != nil { + return err + } else if err := csvWriter.Write(record); err != nil { + return err + } + } + } + csvWriter.Flush() + case utils.MetaResources: + prfx := utils.ResourceProfilesPrefix + keys, err := apiV1.DataManager.DataDB().GetKeysForPrefix(prfx) + if err != nil { + return err + } + if len(keys) == 0 { // if we don't find items we skip + continue + } + f, err := os.Create(path.Join(arg.Path, utils.ResourcesCsv)) + if err != nil { + return err + } + defer f.Close() + + csvWriter := csv.NewWriter(f) + csvWriter.Comma = utils.CSV_SEP + //write the header of the file + if err := csvWriter.Write(engine.TpResources{}.CSVHeader()); err != nil { + return err + } + for _, key := range keys { + tntID := strings.SplitN(key[len(prfx):], utils.InInFieldSep, 2) + resPrf, err := apiV1.DataManager.GetResourceProfile(tntID[0], tntID[1], + true, false, utils.NonTransactional) + if err != nil { + return err + } + for _, model := range engine.APItoModelResource( + engine.ResourceProfileToAPI(resPrf)) { + if record, err := engine.CsvDump(model); err != nil { + return err + } else if err := csvWriter.Write(record); err != nil { + return err + } + } } csvWriter.Flush() } diff --git a/engine/model_helpers.go b/engine/model_helpers.go index 2588eca25..8334c9644 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -131,48 +131,6 @@ func CsvDump(s interface{}) ([]string, error) { return result, nil } -func modelEqual(this interface{}, other interface{}) bool { - var fieldNames []string - st := reflect.TypeOf(this) - stO := reflect.TypeOf(other) - if st != stO { - return false - } - numFields := st.NumField() - for i := 0; i < numFields; i++ { - field := st.Field(i) - index := field.Tag.Get("index") - if index != "" { - fieldNames = append(fieldNames, field.Name) - } - } - thisElem := reflect.ValueOf(this) - otherElem := reflect.ValueOf(other) - for _, fieldName := range fieldNames { - thisField := thisElem.FieldByName(fieldName) - otherField := otherElem.FieldByName(fieldName) - switch thisField.Kind() { - case reflect.Float64: - if thisField.Float() != otherField.Float() { - return false - } - case reflect.Int: - if thisField.Int() != otherField.Int() { - return false - } - case reflect.Bool: - if thisField.Bool() != otherField.Bool() { - return false - } - case reflect.String: - if thisField.String() != otherField.String() { - return false - } - } - } - return true -} - func getColumnCount(s interface{}) int { st := reflect.TypeOf(s) numFields := st.NumField() @@ -1114,6 +1072,13 @@ func APItoModelAccountActions(aas []*utils.TPAccountActions) (result TpAccountAc type TpResources []*TpResource +// CSVHeader return the header for csv fields as a slice of string +func (tps TpResources) CSVHeader() (result []string) { + return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationIntervalString, + utils.UsageTTL, utils.Limit, utils.AllocationMessage, utils.Blocker, utils.Stored, + utils.Weight, utils.ThresholdIDs} +} + func (tps TpResources) AsTPResources() (result []*utils.TPResourceProfile) { mrl := make(map[string]*utils.TPResourceProfile) filterMap := make(map[string]utils.StringMap) @@ -1296,6 +1261,40 @@ func APItoResource(tpRL *utils.TPResourceProfile, timezone string) (rp *Resource return rp, nil } +func ResourceProfileToAPI(rp *ResourceProfile) (tpRL *utils.TPResourceProfile) { + tpRL = &utils.TPResourceProfile{ + Tenant: rp.Tenant, + ID: rp.ID, + FilterIDs: make([]string, len(rp.FilterIDs)), + ActivationInterval: new(utils.TPActivationInterval), + Limit: strconv.FormatFloat(rp.Limit, 'f', -1, 64), + AllocationMessage: rp.AllocationMessage, + Blocker: rp.Blocker, + Stored: rp.Stored, + Weight: rp.Weight, + ThresholdIDs: make([]string, len(rp.ThresholdIDs)), + } + if rp.UsageTTL != time.Duration(0) { + tpRL.UsageTTL = rp.UsageTTL.String() + } + for i, fli := range rp.FilterIDs { + tpRL.FilterIDs[i] = fli + } + for i, fli := range rp.ThresholdIDs { + tpRL.ThresholdIDs[i] = fli + } + + if rp.ActivationInterval != nil { + if !rp.ActivationInterval.ActivationTime.IsZero() { + tpRL.ActivationInterval.ActivationTime = rp.ActivationInterval.ActivationTime.Format(time.RFC3339) + } + if !rp.ActivationInterval.ExpiryTime.IsZero() { + tpRL.ActivationInterval.ExpiryTime = rp.ActivationInterval.ExpiryTime.Format(time.RFC3339) + } + } + return +} + type TpStats []*TpStat func (models TpStats) AsTPStats() (result []*utils.TPStatProfile) { @@ -1672,6 +1671,12 @@ func APItoThresholdProfile(tpTH *utils.TPThresholdProfile, timezone string) (th type TpFilterS []*TpFilter +// CSVHeader return the header for csv fields as a slice of string +func (tps TpFilterS) CSVHeader() (result []string) { + return []string{"#" + utils.Tenant, utils.ID, utils.Type, utils.Element, + utils.Values, utils.ActivationIntervalString} +} + func (tps TpFilterS) AsTPFilter() (result []*utils.TPFilterProfile) { mst := make(map[string]*utils.TPFilterProfile) for _, tp := range tps { @@ -1769,9 +1774,10 @@ func APItoFilter(tpTH *utils.TPFilterProfile, timezone string) (th *Filter, err func FilterToTPFilter(f *Filter) (tpFltr *utils.TPFilterProfile) { tpFltr = &utils.TPFilterProfile{ - Tenant: f.Tenant, - ID: f.ID, - Filters: make([]*utils.TPFilter, len(f.Rules)), + Tenant: f.Tenant, + ID: f.ID, + Filters: make([]*utils.TPFilter, len(f.Rules)), + ActivationInterval: new(utils.TPActivationInterval), } for i, reqFltr := range f.Rules { tpFltr.Filters[i] = &utils.TPFilter{ @@ -2011,7 +2017,11 @@ func APItoSupplierProfile(tpSPP *utils.TPSupplierProfile, timezone string) (spp type TPAttributes []*TPAttribute -// create a function for models that return the CSV header +// CSVHeader return the header for csv fields as a slice of string +func (tps TPAttributes) CSVHeader() (result []string) { + return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationIntervalString, + utils.AttributeFilterIDs, utils.Path, utils.Type, utils.Value, utils.Blocker, utils.Weight} +} func (tps TPAttributes) AsTPAttributes() (result []*utils.TPAttributeProfile) { mst := make(map[string]*utils.TPAttributeProfile) @@ -2179,7 +2189,6 @@ func APItoAttributeProfile(tpAttr *utils.TPAttributeProfile, timezone string) (a func AttributeProfileToAPI(attrPrf *AttributeProfile) (tpAttr *utils.TPAttributeProfile) { tpAttr = &utils.TPAttributeProfile{ - TPid: utils.EmptyString, Tenant: attrPrf.Tenant, ID: attrPrf.ID, FilterIDs: make([]string, len(attrPrf.FilterIDs)), @@ -2216,6 +2225,12 @@ func AttributeProfileToAPI(attrPrf *AttributeProfile) (tpAttr *utils.TPAttribute type TPChargers []*TPCharger +// CSVHeader return the header for csv fields as a slice of string +func (tps TPChargers) CSVHeader() (result []string) { + return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs, utils.ActivationIntervalString, + utils.RunID, utils.AttributeIDs, utils.Weight} +} + func (tps TPChargers) AsTPChargers() (result []*utils.TPChargerProfile) { mst := make(map[string]*utils.TPChargerProfile) filterMap := make(map[string]utils.StringMap) @@ -2385,8 +2400,42 @@ func APItoChargerProfile(tpCPP *utils.TPChargerProfile, timezone string) (cpp *C return cpp, nil } +func ChargerProfileToAPI(chargerPrf *ChargerProfile) (tpCharger *utils.TPChargerProfile) { + tpCharger = &utils.TPChargerProfile{ + Tenant: chargerPrf.Tenant, + ID: chargerPrf.ID, + FilterIDs: make([]string, len(chargerPrf.FilterIDs)), + ActivationInterval: new(utils.TPActivationInterval), + RunID: chargerPrf.RunID, + AttributeIDs: make([]string, len(chargerPrf.AttributeIDs)), + Weight: chargerPrf.Weight, + } + for i, fli := range chargerPrf.FilterIDs { + tpCharger.FilterIDs[i] = fli + } + for i, fli := range chargerPrf.AttributeIDs { + tpCharger.AttributeIDs[i] = fli + } + if chargerPrf.ActivationInterval != nil { + if !chargerPrf.ActivationInterval.ActivationTime.IsZero() { + tpCharger.ActivationInterval.ActivationTime = chargerPrf.ActivationInterval.ActivationTime.Format(time.RFC3339) + } + if !chargerPrf.ActivationInterval.ExpiryTime.IsZero() { + tpCharger.ActivationInterval.ExpiryTime = chargerPrf.ActivationInterval.ExpiryTime.Format(time.RFC3339) + } + } + return +} + type TPDispatcherProfiles []*TPDispatcherProfile +// CSVHeader return the header for csv fields as a slice of string +func (tps TPDispatcherProfiles) CSVHeader() (result []string) { + return []string{"#" + utils.Tenant, utils.ID, utils.Subsystems, utils.FilterIDs, utils.ActivationIntervalString, + utils.Strategy, utils.StrategyParameters, utils.ConnID, utils.ConnFilterIDs, + utils.ConnWeight, utils.ConnBlocker, utils.ConnParameters, utils.Weight} +} + func (tps TPDispatcherProfiles) AsTPDispatcherProfiles() (result []*utils.TPDispatcherProfile) { mst := make(map[string]*utils.TPDispatcherProfile) filterMap := make(map[string]utils.StringMap) @@ -2642,9 +2691,73 @@ func APItoDispatcherProfile(tpDPP *utils.TPDispatcherProfile, timezone string) ( return dpp, nil } +func DispatcherProfileToAPI(dpp *DispatcherProfile) (tpDPP *utils.TPDispatcherProfile) { + tpDPP = &utils.TPDispatcherProfile{ + Tenant: dpp.Tenant, + ID: dpp.ID, + Subsystems: make([]string, len(dpp.Subsystems)), + FilterIDs: make([]string, len(dpp.FilterIDs)), + ActivationInterval: new(utils.TPActivationInterval), + Strategy: dpp.Strategy, + StrategyParams: make([]interface{}, len(dpp.StrategyParams)), + Weight: dpp.Weight, + Hosts: make([]*utils.TPDispatcherHostProfile, len(dpp.Hosts)), + } + + for i, fli := range dpp.FilterIDs { + tpDPP.FilterIDs[i] = fli + } + for i, sub := range dpp.Subsystems { + tpDPP.Subsystems[i] = sub + } + for key, val := range dpp.StrategyParams { + // here we expect that the key to be an integer because + // according to APItoDispatcherProfile when we convert from TP to obj we use index as key + // so we can ignore error + idx, _ := strconv.Atoi(key) + tpDPP.StrategyParams[idx] = val + } + for i, host := range dpp.Hosts { + tpDPP.Hosts[i] = &utils.TPDispatcherHostProfile{ + ID: host.ID, + FilterIDs: make([]string, len(host.FilterIDs)), + Weight: host.Weight, + Params: make([]interface{}, len(host.Params)), + Blocker: host.Blocker, + } + for j, fltr := range host.FilterIDs { + tpDPP.Hosts[i].FilterIDs[j] = fltr + } + idx := 0 + for key, val := range host.Params { + paramVal := val + if _, err := strconv.Atoi(key); err != nil { + paramVal = utils.ConcatenatedKey(key, utils.IfaceAsString(val)) + } + tpDPP.Hosts[i].Params[idx] = paramVal + idx++ + } + } + + if dpp.ActivationInterval != nil { + if !dpp.ActivationInterval.ActivationTime.IsZero() { + tpDPP.ActivationInterval.ActivationTime = dpp.ActivationInterval.ActivationTime.Format(time.RFC3339) + } + if !dpp.ActivationInterval.ExpiryTime.IsZero() { + tpDPP.ActivationInterval.ExpiryTime = dpp.ActivationInterval.ExpiryTime.Format(time.RFC3339) + } + } + return +} + // TPHosts type TPDispatcherHosts []*TPDispatcherHost +// CSVHeader return the header for csv fields as a slice of string +func (tps TPDispatcherHosts) CSVHeader() (result []string) { + return []string{"#" + utils.Tenant, utils.ID, utils.Address, utils.Transport, utils.TLS} +} + func (tps TPDispatcherHosts) AsTPDispatcherHosts() (result []*utils.TPDispatcherHost) { hostsMap := make(map[string]*utils.TPDispatcherHost) for _, tp := range tps { @@ -2718,3 +2831,20 @@ func APItoDispatcherHost(tpDPH *utils.TPDispatcherHost) (dpp *DispatcherHost) { } return } + +func DispatcherHostToAPI(dph *DispatcherHost) (tpDPH *utils.TPDispatcherHost) { + tpDPH = &utils.TPDispatcherHost{ + Tenant: dph.Tenant, + ID: dph.ID, + Conns: make([]*utils.TPDispatcherHostConn, len(dph.Conns)), + } + + for i, conn := range dph.Conns { + tpDPH.Conns[i] = &utils.TPDispatcherHostConn{ + Address: conn.Address, + Transport: conn.Transport, + TLS: conn.TLS, + } + } + return +} diff --git a/engine/model_helpers_test.go b/engine/model_helpers_test.go index 426885b9d..60188ec95 100644 --- a/engine/model_helpers_test.go +++ b/engine/model_helpers_test.go @@ -561,6 +561,35 @@ func TestAPItoResource(t *testing.T) { } } +func TestResourceProfileToAPI(t *testing.T) { + expected := &utils.TPResourceProfile{ + Tenant: "cgrates.org", + ID: "ResGroup1", + FilterIDs: []string{"FLTR_RES_GR_1"}, + ActivationInterval: &utils.TPActivationInterval{ActivationTime: "2014-07-29T15:00:00Z"}, + Weight: 10, + Limit: "2", + ThresholdIDs: []string{"TRes1"}, + AllocationMessage: "asd", + } + rp := &ResourceProfile{ + Tenant: "cgrates.org", + ID: "ResGroup1", + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 29, 15, 0, 0, 0, time.UTC), + }, + Weight: 10, + FilterIDs: []string{"FLTR_RES_GR_1"}, + ThresholdIDs: []string{"TRes1"}, + AllocationMessage: "asd", + Limit: 2, + } + + if rcv := ResourceProfileToAPI(rp); !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting: %+v, \n received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv)) + } +} + func TestAPItoModelResource(t *testing.T) { tpRL := &utils.TPResourceProfile{ Tenant: "cgrates.org", @@ -1366,6 +1395,65 @@ func TestAPItoModelTPAttribute(t *testing.T) { } } +func TestCsvDumpForAttributeModels(t *testing.T) { + tpAlsPrf := &utils.TPAttributeProfile{ + TPid: "TP1", + Tenant: "cgrates.org", + ID: "ALS1", + Contexts: []string{"con1"}, + FilterIDs: []string{"FLTR_ACNT_dan"}, + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-07-14T14:35:00Z", + ExpiryTime: "", + }, + Attributes: []*utils.TPAttribute{ + &utils.TPAttribute{ + Path: utils.MetaReq + utils.NestingSep + "FL1", + Value: "Al1", + }, + &utils.TPAttribute{ + Path: utils.MetaReq + utils.NestingSep + "FL2", + Value: "Al2", + }, + }, + Weight: 20, + } + expected := TPAttributes{ + &TPAttribute{ + Tpid: "TP1", + Tenant: "cgrates.org", + ID: "ALS1", + Contexts: "con1", + FilterIDs: "FLTR_ACNT_dan", + Path: utils.MetaReq + utils.NestingSep + "FL1", + Value: "Al1", + ActivationInterval: "2014-07-14T14:35:00Z", + Weight: 20, + }, + &TPAttribute{ + Tpid: "TP1", + Tenant: "cgrates.org", + ID: "ALS1", + Path: utils.MetaReq + utils.NestingSep + "FL2", + Value: "Al2", + }, + } + rcv := APItoModelTPAttribute(tpAlsPrf) + if !reflect.DeepEqual(expected, rcv) { + t.Errorf("Expecting : %+v,\n received: %+v", utils.ToJSON(expected), utils.ToJSON(rcv)) + } + expRecord := []string{"cgrates.org", "ALS1", "con1", "FLTR_ACNT_dan", "2014-07-14T14:35:00Z", "", "*req.FL1", "", "Al1", "false", "20"} + for i, model := range rcv { + if i == 1 { + expRecord = []string{"cgrates.org", "ALS1", "", "", "", "", "*req.FL2", "", "Al2", "false", "0"} + } + if csvRecordRcv, _ := CsvDump(model); !reflect.DeepEqual(expRecord, csvRecordRcv) { + t.Errorf("Expecting : %+v, received: %+v", utils.ToJSON(expRecord), utils.ToJSON(csvRecordRcv)) + } + } + +} + func TestModelAsTPAttribute(t *testing.T) { models := TPAttributes{ &TPAttribute{ @@ -1457,6 +1545,38 @@ func TestAPItoChargerProfile(t *testing.T) { } } +func TestChargerProfileToAPI(t *testing.T) { + exp := &utils.TPChargerProfile{ + Tenant: "cgrates.org", + ID: "Charger1", + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + RunID: "*rated", + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-07-14T14:35:00Z", + ExpiryTime: "", + }, + AttributeIDs: []string{"ATTR1", "ATTR2"}, + Weight: 20, + } + + chargerPrf := &ChargerProfile{ + Tenant: "cgrates.org", + ID: "Charger1", + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), + }, + RunID: "*rated", + AttributeIDs: []string{"ATTR1", "ATTR2"}, + Weight: 20, + } + if rcv := ChargerProfileToAPI(chargerPrf); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(exp, rcv) { + t.Errorf("Expecting : %+v, \n received: %+v", utils.ToJSON(exp), utils.ToJSON(rcv)) + } +} + //Number of FilterIDs and AttributeIDs are equal func TestAPItoModelTPCharger(t *testing.T) { tpCharger := &utils.TPChargerProfile{ @@ -1766,6 +1886,80 @@ func TestAPItoDispatcherProfile(t *testing.T) { } } +func TestDispatcherProfileToAPI(t *testing.T) { + exp := &utils.TPDispatcherProfile{ + Tenant: "cgrates.org", + ID: "Dsp", + Subsystems: []string{"*any"}, + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + Strategy: utils.MetaFirst, + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-07-14T14:35:00Z", + ExpiryTime: "", + }, + StrategyParams: []interface{}{}, + Weight: 20, + Hosts: []*utils.TPDispatcherHostProfile{ + &utils.TPDispatcherHostProfile{ + ID: "C1", + FilterIDs: []string{}, + Weight: 10, + Params: []interface{}{"192.168.54.203", "*ratio:2"}, + Blocker: false, + }, + }, + } + exp2 := &utils.TPDispatcherProfile{ + Tenant: "cgrates.org", + ID: "Dsp", + Subsystems: []string{"*any"}, + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + Strategy: utils.MetaFirst, + ActivationInterval: &utils.TPActivationInterval{ + ActivationTime: "2014-07-14T14:35:00Z", + ExpiryTime: "", + }, + StrategyParams: []interface{}{}, + Weight: 20, + Hosts: []*utils.TPDispatcherHostProfile{ + &utils.TPDispatcherHostProfile{ + ID: "C1", + FilterIDs: []string{}, + Weight: 10, + Params: []interface{}{"*ratio:2", "192.168.54.203"}, + Blocker: false, + }, + }, + } + + dspPrf := &DispatcherProfile{ + Tenant: "cgrates.org", + ID: "Dsp", + Subsystems: []string{"*any"}, + FilterIDs: []string{"FLTR_ACNT_dan", "FLTR_DST_DE"}, + Strategy: utils.MetaFirst, + ActivationInterval: &utils.ActivationInterval{ + ActivationTime: time.Date(2014, 7, 14, 14, 35, 0, 0, time.UTC), + }, + StrategyParams: map[string]interface{}{}, + Weight: 20, + Hosts: DispatcherHostProfiles{ + &DispatcherHostProfile{ + ID: "C1", + FilterIDs: []string{}, + Weight: 10, + Params: map[string]interface{}{"0": "192.168.54.203", utils.MetaRatio: "2"}, + Blocker: false, + }, + }, + } + if rcv := DispatcherProfileToAPI(dspPrf); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(exp, rcv) && !reflect.DeepEqual(exp2, rcv) { + t.Errorf("Expecting : \n %+v \n or \n %+v \n ,\n received: %+v", utils.ToJSON(exp), utils.ToJSON(exp2), utils.ToJSON(rcv)) + } +} + func TestAPItoModelTPDispatcher(t *testing.T) { tpDPP := &utils.TPDispatcherProfile{ TPid: "TP1", diff --git a/utils/consts.go b/utils/consts.go index e5c9699eb..5362e3b0c 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -207,6 +207,7 @@ const ( PDD = "PDD" SUPPLIER = "Supplier" RunID = "RunID" + AttributeIDs = "AttributeIDs" MetaReqRunID = "*req.RunID" COST = "Cost" CostDetails = "CostDetails" @@ -423,247 +424,266 @@ const ( MetaEveryMinute = "*every_minute" MetaHourly = "*hourly" ID = "ID" - Thresholds = "Thresholds" - Suppliers = "Suppliers" - Attributes = "Attributes" - Chargers = "Chargers" - Dispatchers = "Dispatchers" - StatS = "Stats" - LoadIDsVrs = "LoadIDs" - RALService = "RALs" - CostSource = "CostSource" - ExtraInfo = "ExtraInfo" - Meta = "*" - MetaSysLog = "*syslog" - MetaStdLog = "*stdout" - EventType = "EventType" - EventSource = "EventSource" - AccountID = "AccountID" - ResourceID = "ResourceID" - TotalUsage = "TotalUsage" - StatID = "StatID" - BalanceType = "BalanceType" - BalanceID = "BalanceID" - BalanceDestinationIds = "BalanceDestinationIds" - BalanceWeight = "BalanceWeight" - BalanceExpirationDate = "BalanceExpirationDate" - BalanceTimingTags = "BalanceTimingTags" - BalanceRatingSubject = "BalanceRatingSubject" - BalanceCategories = "BalanceCategories" - BalanceSharedGroups = "BalanceSharedGroups" - BalanceBlocker = "BalanceBlocker" - BalanceDisabled = "BalanceDisabled" - Units = "Units" - AccountUpdate = "AccountUpdate" - BalanceUpdate = "BalanceUpdate" - StatUpdate = "StatUpdate" - ResourceUpdate = "ResourceUpdate" - CDR = "CDR" - CDRs = "CDRs" - ExpiryTime = "ExpiryTime" - AllowNegative = "AllowNegative" - Disabled = "Disabled" - Action = "Action" - MetaNow = "*now" - SessionSCosts = "SessionSCosts" - Timing = "Timing" - RQF = "RQF" - Resource = "Resource" - User = "User" - Subscribers = "Subscribers" - DerivedChargersV = "DerivedChargers" - Destinations = "Destinations" - ReverseDestinations = "ReverseDestinations" - RatingPlan = "RatingPlan" - RatingProfile = "RatingProfile" - MetaRatingPlans = "*rating_plans" - MetaRatingProfiles = "*rating_profiles" - MetaUsers = "*users" - MetaSubscribers = "*subscribers" - MetaDerivedChargersV = "*derivedchargers" - MetaStorDB = "*stordb" - MetaDataDB = "*datadb" - MetaWeight = "*weight" - MetaLC = "*lc" - MetaHC = "*hc" - MetaQOS = "*qos" - MetaReas = "*reas" - MetaReds = "*reds" - Weight = "Weight" - Cost = "Cost" - DestinationIDs = "DestinationIDs" - RatingSubject = "RatingSubject" - Categories = "Categories" - Blocker = "Blocker" - RatingPlanID = "RatingPlanID" - StartTime = "StartTime" - AccountSummary = "AccountSummary" - RatingFilters = "RatingFilters" - RatingFilter = "RatingFilter" - Accounting = "Accounting" - Rating = "Rating" - Charges = "Charges" - CompressFactor = "CompressFactor" - Increments = "Increments" - Balance = "Balance" - BalanceSummaries = "BalanceSummaries" - Type = "Type" - YearsFieldName = "Years" - MonthsFieldName = "Months" - MonthDaysFieldName = "MonthDays" - WeekDaysFieldName = "WeekDays" - GroupIntervalStart = "GroupIntervalStart" - RateIncrement = "RateIncrement" - RateUnit = "RateUnit" - BalanceUUID = "BalanceUUID" - RatingID = "RatingID" - ExtraChargeID = "ExtraChargeID" - ConnectFee = "ConnectFee" - RoundingMethod = "RoundingMethod" - RoundingDecimals = "RoundingDecimals" - MaxCostStrategy = "MaxCostStrategy" - TimingID = "TimingID" - RatesID = "RatesID" - RatingFiltersID = "RatingFiltersID" - AccountingID = "AccountingID" - MetaSessionS = "*sessions" - MetaDefault = "*default" - Error = "Error" - MetaCgreq = "*cgreq" - MetaCgrep = "*cgrep" - MetaCGRAReq = "*cgrareq" - CGR_ACD = "cgr_acd" - FilterIDs = "FilterIDs" - ActivationInternal = "ActivationInterval" - AttributeFilterIDs = "AttributeFilterIDs" - FieldName = "FieldName" - Path = "Path" - MetaRound = "*round" - Pong = "Pong" - MetaEventCost = "*event_cost" - MetaSuppliersEventCost = "*suppliers_event_cost" - MetaSuppliersIgnoreErrors = "*suppliers_ignore_errors" - Freeswitch = "freeswitch" - Kamailio = "kamailio" - Opensips = "opensips" - Asterisk = "asterisk" - SchedulerS = "SchedulerS" - MetaMultiply = "*multiply" - MetaDivide = "*divide" - MetaUrl = "*url" - MetaXml = "*xml" - ApiKey = "apikey" - MetaReq = "*req" - MetaVars = "*vars" - MetaRep = "*rep" - MetaExp = "*exp" - MetaHdr = "*hdr" - MetaTrl = "*trl" - MetaTmp = "*tmp" - CGROriginHost = "cgr_originhost" - MetaInitiate = "*initiate" - MetaUpdate = "*update" - MetaTerminate = "*terminate" - MetaEvent = "*event" - MetaMessage = "*message" - MetaDryRun = "*dryrun" - Event = "Event" - EmptyString = "" - DynamicDataPrefix = "~" - AttrValueSep = "=" - ANDSep = "&" - PipeSep = "|" - MetaApp = "*app" - MetaAppID = "*appid" - MetaCmd = "*cmd" - MetaEnv = "*env:" // use in config for describing enviormant variables - MetaTemplate = "*template" - MetaCCA = "*cca" - MetaErr = "*err" - OriginRealm = "OriginRealm" - ProductName = "ProductName" - IdxStart = "[" - IdxEnd = "]" - MetaLog = "*log" - MetaRemoteHost = "*remote_host" - RemoteHost = "RemoteHost" - Local = "local" - TCP = "tcp" - CGRDebitInterval = "CGRDebitInterval" - Version = "Version" - MetaTenant = "*tenant" - ResourceUsage = "ResourceUsage" - MetaDuration = "*duration" - MetaLibPhoneNumber = "*libphonenumber" - MetaIP2Hex = "*ip2hex" - MetaReload = "*reload" - MetaLoad = "*load" - MetaRemove = "*remove" - MetaStore = "*store" - MetaClear = "*clear" - MetaExport = "*export" - LoadIDs = "load_ids" - DNSAgent = "DNSAgent" - TLSNoCaps = "tls" - MetaRouteID = "*route_id" - MetaApiKey = "*api_key" - UsageID = "UsageID" - Rcode = "Rcode" - Replacement = "Replacement" - Regexp = "Regexp" - Order = "Order" - Preference = "Preference" - Flags = "Flags" - Service = "Service" - MetaSuppliersLimit = "*suppliers_limit" - MetaSuppliersOffset = "*suppliers_offset" - ApierV = "ApierV" - MetaApier = "*apier" - MetaAnalyzer = "*analyzer" - CGREventString = "CGREvent" - MetaTextPlain = "*text_plain" - MetaIgnoreErrors = "*ignore_errors" - MetaRelease = "*release" - MetaAllocate = "*allocate" - MetaAuthorize = "*authorize" - MetaInit = "*init" - MetaRatingPlanCost = "*rating_plan_cost" - RatingPlanIDs = "RatingPlanIDs" - ERs = "ERs" - Ratio = "Ratio" - Load = "Load" - Slash = "/" - UUID = "UUID" - ActionsID = "ActionsID" - MetaAct = "*act" - DestinationPrefix = "DestinationPrefix" - DestinationID = "DestinationID" - ExportTemplate = "ExportTemplate" - ExportFormat = "ExportFormat" - Synchronous = "Synchronous" - Attempts = "Attempts" - FieldSeparator = "FieldSeparator" - ExportPath = "ExportPath" - ExportID = "ExportID" - ExportFileName = "ExportFileName" - GroupID = "GroupID" - ThresholdType = "ThresholdType" - ThresholdValue = "ThresholdValue" - Recurrent = "Recurrent" - Executed = "Executed" - MinSleep = "MinSleep" - ActivationDate = "ActivationDate" - ExpirationDate = "ExpirationDate" - MinQueuedItems = "MinQueuedItems" - OrderIDStart = "OrderIDStart" - OrderIDEnd = "OrderIDEnd" - MinCost = "MinCost" - MaxCost = "MaxCost" - MetaLoaders = "*loaders" - TmpSuffix = ".tmp" - MetaDiamreq = "*diamreq" - MetaCost = "*cost" - MetaGroup = "*group" + Address = "Address" + Transport = "Transport" + TLS = "TLS" + Subsystems = "Subsystems" + Strategy = "Strategy" + StrategyParameters = "StrategyParameters" + ConnID = "ConnID" + ConnFilterIDs = "ConnFilterIDs" + ConnWeight = "ConnWeight" + ConnBlocker = "ConnBlocker" + ConnParameters = "ConnParameters" + + Thresholds = "Thresholds" + Suppliers = "Suppliers" + Attributes = "Attributes" + Chargers = "Chargers" + Dispatchers = "Dispatchers" + StatS = "Stats" + LoadIDsVrs = "LoadIDs" + RALService = "RALs" + CostSource = "CostSource" + ExtraInfo = "ExtraInfo" + Meta = "*" + MetaSysLog = "*syslog" + MetaStdLog = "*stdout" + EventType = "EventType" + EventSource = "EventSource" + AccountID = "AccountID" + ResourceID = "ResourceID" + TotalUsage = "TotalUsage" + StatID = "StatID" + BalanceType = "BalanceType" + BalanceID = "BalanceID" + BalanceDestinationIds = "BalanceDestinationIds" + BalanceWeight = "BalanceWeight" + BalanceExpirationDate = "BalanceExpirationDate" + BalanceTimingTags = "BalanceTimingTags" + BalanceRatingSubject = "BalanceRatingSubject" + BalanceCategories = "BalanceCategories" + BalanceSharedGroups = "BalanceSharedGroups" + BalanceBlocker = "BalanceBlocker" + BalanceDisabled = "BalanceDisabled" + Units = "Units" + AccountUpdate = "AccountUpdate" + BalanceUpdate = "BalanceUpdate" + StatUpdate = "StatUpdate" + ResourceUpdate = "ResourceUpdate" + CDR = "CDR" + CDRs = "CDRs" + ExpiryTime = "ExpiryTime" + AllowNegative = "AllowNegative" + Disabled = "Disabled" + Action = "Action" + MetaNow = "*now" + SessionSCosts = "SessionSCosts" + Timing = "Timing" + RQF = "RQF" + Resource = "Resource" + User = "User" + Subscribers = "Subscribers" + DerivedChargersV = "DerivedChargers" + Destinations = "Destinations" + ReverseDestinations = "ReverseDestinations" + RatingPlan = "RatingPlan" + RatingProfile = "RatingProfile" + MetaRatingPlans = "*rating_plans" + MetaRatingProfiles = "*rating_profiles" + MetaUsers = "*users" + MetaSubscribers = "*subscribers" + MetaDerivedChargersV = "*derivedchargers" + MetaStorDB = "*stordb" + MetaDataDB = "*datadb" + MetaWeight = "*weight" + MetaLC = "*lc" + MetaHC = "*hc" + MetaQOS = "*qos" + MetaReas = "*reas" + MetaReds = "*reds" + Weight = "Weight" + ThresholdIDs = "ThresholdIDs" + Cost = "Cost" + Limit = "Limit" + UsageTTL = "UsageTTL" + AllocationMessage = "AllocationMessage" + Stored = "Stored" + DestinationIDs = "DestinationIDs" + RatingSubject = "RatingSubject" + Categories = "Categories" + Blocker = "Blocker" + RatingPlanID = "RatingPlanID" + StartTime = "StartTime" + AccountSummary = "AccountSummary" + RatingFilters = "RatingFilters" + RatingFilter = "RatingFilter" + Accounting = "Accounting" + Rating = "Rating" + Charges = "Charges" + CompressFactor = "CompressFactor" + Increments = "Increments" + Balance = "Balance" + BalanceSummaries = "BalanceSummaries" + Type = "Type" + Element = "Element" + Values = "Values" + YearsFieldName = "Years" + MonthsFieldName = "Months" + MonthDaysFieldName = "MonthDays" + WeekDaysFieldName = "WeekDays" + GroupIntervalStart = "GroupIntervalStart" + RateIncrement = "RateIncrement" + RateUnit = "RateUnit" + BalanceUUID = "BalanceUUID" + RatingID = "RatingID" + ExtraChargeID = "ExtraChargeID" + ConnectFee = "ConnectFee" + RoundingMethod = "RoundingMethod" + RoundingDecimals = "RoundingDecimals" + MaxCostStrategy = "MaxCostStrategy" + TimingID = "TimingID" + RatesID = "RatesID" + RatingFiltersID = "RatingFiltersID" + AccountingID = "AccountingID" + MetaSessionS = "*sessions" + MetaDefault = "*default" + Error = "Error" + MetaCgreq = "*cgreq" + MetaCgrep = "*cgrep" + MetaCGRAReq = "*cgrareq" + CGR_ACD = "cgr_acd" + FilterIDs = "FilterIDs" + ActivationIntervalString = "ActivationInterval" + AttributeFilterIDs = "AttributeFilterIDs" + FieldName = "FieldName" + Path = "Path" + MetaRound = "*round" + Pong = "Pong" + MetaEventCost = "*event_cost" + MetaSuppliersEventCost = "*suppliers_event_cost" + MetaSuppliersIgnoreErrors = "*suppliers_ignore_errors" + Freeswitch = "freeswitch" + Kamailio = "kamailio" + Opensips = "opensips" + Asterisk = "asterisk" + SchedulerS = "SchedulerS" + MetaMultiply = "*multiply" + MetaDivide = "*divide" + MetaUrl = "*url" + MetaXml = "*xml" + ApiKey = "apikey" + MetaReq = "*req" + MetaVars = "*vars" + MetaRep = "*rep" + MetaExp = "*exp" + MetaHdr = "*hdr" + MetaTrl = "*trl" + MetaTmp = "*tmp" + CGROriginHost = "cgr_originhost" + MetaInitiate = "*initiate" + MetaUpdate = "*update" + MetaTerminate = "*terminate" + MetaEvent = "*event" + MetaMessage = "*message" + MetaDryRun = "*dryrun" + Event = "Event" + EmptyString = "" + DynamicDataPrefix = "~" + AttrValueSep = "=" + ANDSep = "&" + PipeSep = "|" + MetaApp = "*app" + MetaAppID = "*appid" + MetaCmd = "*cmd" + MetaEnv = "*env:" // use in config for describing enviormant variables + MetaTemplate = "*template" + MetaCCA = "*cca" + MetaErr = "*err" + OriginRealm = "OriginRealm" + ProductName = "ProductName" + IdxStart = "[" + IdxEnd = "]" + MetaLog = "*log" + MetaRemoteHost = "*remote_host" + RemoteHost = "RemoteHost" + Local = "local" + TCP = "tcp" + CGRDebitInterval = "CGRDebitInterval" + Version = "Version" + MetaTenant = "*tenant" + ResourceUsage = "ResourceUsage" + MetaDuration = "*duration" + MetaLibPhoneNumber = "*libphonenumber" + MetaIP2Hex = "*ip2hex" + MetaReload = "*reload" + MetaLoad = "*load" + MetaRemove = "*remove" + MetaStore = "*store" + MetaClear = "*clear" + MetaExport = "*export" + LoadIDs = "load_ids" + DNSAgent = "DNSAgent" + TLSNoCaps = "tls" + MetaRouteID = "*route_id" + MetaApiKey = "*api_key" + UsageID = "UsageID" + Rcode = "Rcode" + Replacement = "Replacement" + Regexp = "Regexp" + Order = "Order" + Preference = "Preference" + Flags = "Flags" + Service = "Service" + MetaSuppliersLimit = "*suppliers_limit" + MetaSuppliersOffset = "*suppliers_offset" + ApierV = "ApierV" + MetaApier = "*apier" + MetaAnalyzer = "*analyzer" + CGREventString = "CGREvent" + MetaTextPlain = "*text_plain" + MetaIgnoreErrors = "*ignore_errors" + MetaRelease = "*release" + MetaAllocate = "*allocate" + MetaAuthorize = "*authorize" + MetaInit = "*init" + MetaRatingPlanCost = "*rating_plan_cost" + RatingPlanIDs = "RatingPlanIDs" + ERs = "ERs" + Ratio = "Ratio" + Load = "Load" + Slash = "/" + UUID = "UUID" + ActionsID = "ActionsID" + MetaAct = "*act" + DestinationPrefix = "DestinationPrefix" + DestinationID = "DestinationID" + ExportTemplate = "ExportTemplate" + ExportFormat = "ExportFormat" + Synchronous = "Synchronous" + Attempts = "Attempts" + FieldSeparator = "FieldSeparator" + ExportPath = "ExportPath" + ExportID = "ExportID" + ExportFileName = "ExportFileName" + GroupID = "GroupID" + ThresholdType = "ThresholdType" + ThresholdValue = "ThresholdValue" + Recurrent = "Recurrent" + Executed = "Executed" + MinSleep = "MinSleep" + ActivationDate = "ActivationDate" + ExpirationDate = "ExpirationDate" + MinQueuedItems = "MinQueuedItems" + OrderIDStart = "OrderIDStart" + OrderIDEnd = "OrderIDEnd" + MinCost = "MinCost" + MaxCost = "MaxCost" + MetaLoaders = "*loaders" + TmpSuffix = ".tmp" + MetaDiamreq = "*diamreq" + MetaCost = "*cost" + MetaGroup = "*group" InternalRPCSet = "InternalRPCSet" )