예제 #1
0
// Returns the aliases of one specific account on a tenant
func (rs *RedisStorage) GetAccountAliases(tenant, account string, skipCache bool) (aliases []string, err error) {
	tenantPrfx := ACC_ALIAS_PREFIX + tenant + utils.CONCATENATED_KEY_SEP
	var alsKeys []string
	if !skipCache {
		alsKeys = cache2go.GetEntriesKeys(tenantPrfx)
	}
	if len(alsKeys) == 0 {
		if alsKeys, err = rs.db.Keys(tenantPrfx + "*"); err != nil {
			return nil, err
		}
	}
	for _, key := range alsKeys {
		if alsAcnt, err := rs.GetAccAlias(key[len(ACC_ALIAS_PREFIX):], skipCache); err != nil {
			return nil, err
		} else if alsAcnt == account {
			alsFromKey := key[len(tenantPrfx):] // take out the alias out of key+tenant
			aliases = append(aliases, alsFromKey)
		}
	}
	return aliases, nil
}
예제 #2
0
func (ms *MapStorage) GetRPAliases(tenant, subject string, skipCache bool) (aliases []string, err error) {
	tenantPrfx := RP_ALIAS_PREFIX + tenant + utils.CONCATENATED_KEY_SEP
	var alsKeys []string
	if !skipCache {
		alsKeys = cache2go.GetEntriesKeys(tenantPrfx)
	}
	for _, key := range alsKeys {
		if alsSubj, err := ms.GetRpAlias(key[len(RP_ALIAS_PREFIX):], skipCache); err != nil {
			return nil, err
		} else if alsSubj == subject {
			alsFromKey := key[len(tenantPrfx):] // take out the alias out of key+tenant
			aliases = append(aliases, alsFromKey)
		}
	}
	if len(alsKeys) == 0 {
		for key, value := range ms.dict {
			if strings.HasPrefix(key, RP_ALIAS_PREFIX) && len(key) >= len(tenantPrfx) && key[:len(tenantPrfx)] == tenantPrfx && subject == string(value) {
				aliases = append(aliases, key[len(tenantPrfx):])
			}
		}
	}
	return aliases, nil
}
예제 #3
0
func (cd *CallDescriptor) GetLCR(stats StatsInterface, p *utils.Paginator) (*LCRCost, error) {
	cd.account = nil // make sure it's not cached
	lcr, err := cd.GetLCRFromStorage()
	if err != nil {
		return nil, err
	}
	// sort by activation time
	lcr.Sort()
	// find if one ore more entries apply to this cd (create lcr timespans)
	// create timespans and attach lcr entries to them
	lcrCost := &LCRCost{}
	for _, lcrActivation := range lcr.Activations {
		//log.Printf("Activation: %+v", lcrActivation)
		lcrEntry := lcrActivation.GetLCREntryForPrefix(cd.Destination)
		//log.Printf("Entry: %+v", lcrEntry)
		if lcrActivation.ActivationTime.Before(cd.TimeStart) ||
			lcrActivation.ActivationTime.Equal(cd.TimeStart) {
			lcrCost.Entry = lcrEntry
		} else {
			// because lcr is sorted the folowing ones will
			// only activate later than cd.Timestart
			break
		}
	}
	if lcrCost.Entry == nil {
		return lcrCost, nil
	}

	//log.Printf("Entry: %+v", lcrCost.Entry)
	if lcrCost.Entry.Strategy == LCR_STRATEGY_STATIC {
		for _, supplier := range lcrCost.Entry.GetParams() {
			lcrCD := cd.Clone()
			lcrCD.Account = supplier
			lcrCD.Subject = supplier
			lcrCD.Category = lcrCost.Entry.RPCategory
			fullSupplier := utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
			var cc *CallCost
			var err error
			if cd.account, err = accountingStorage.GetAccount(lcrCD.GetAccountKey()); err == nil {
				if cd.account.Disabled {
					lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
						Supplier: fullSupplier,
						Error:    fmt.Sprintf("supplier %s is disabled", supplier),
					})
					continue
				}
				cc, err = lcrCD.debit(cd.account, true, true)
			} else {
				cc, err = lcrCD.GetCost()
			}
			//log.Printf("CC: %+v", cc.Timespans[0].ratingInfo.RateIntervals[0].Rating.Rates[0])
			if err != nil || cc == nil {
				lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
					Supplier: fullSupplier,
					Error:    err.Error(),
				})
			} else {
				lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
					Supplier: fullSupplier,
					Cost:     cc.Cost,
					Duration: cc.GetDuration(),
				})
			}
		}
	} else {
		// find rating profiles
		category := lcrCost.Entry.RPCategory
		if category == utils.META_DEFAULT {
			category = lcr.Category
		}
		ratingProfileSearchKey := utils.ConcatenatedKey(lcr.Direction, lcr.Tenant, lcrCost.Entry.RPCategory)
		//log.Print("KEY: ", ratingProfileSearchKey)
		suppliers := cache2go.GetEntriesKeys(utils.RATING_PROFILE_PREFIX + ratingProfileSearchKey)
		for _, supplier := range suppliers {
			//log.Print("Supplier: ", supplier)
			split := strings.Split(supplier, ":")
			supplier = split[len(split)-1]
			lcrCD := cd.Clone()
			lcrCD.Category = category
			lcrCD.Account = supplier
			lcrCD.Subject = supplier
			fullSupplier := utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
			var qosSortParams []string
			var asrValues sort.Float64Slice
			var pddValues sort.Float64Slice
			var acdValues sort.Float64Slice
			var tcdValues sort.Float64Slice
			var accValues sort.Float64Slice
			var tccValues sort.Float64Slice
			var ddcValues sort.Float64Slice
			// track if one value is never calculated
			asrNeverConsidered := true
			pddNeverConsidered := true
			acdNeverConsidered := true
			tcdNeverConsidered := true
			accNeverConsidered := true
			tccNeverConsidered := true
			ddcNeverConsidered := true
			if utils.IsSliceMember([]string{LCR_STRATEGY_QOS, LCR_STRATEGY_QOS_THRESHOLD, LCR_STRATEGY_LOAD}, lcrCost.Entry.Strategy) {
				if stats == nil {
					lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
						Supplier: fullSupplier,
						Error:    fmt.Sprintf("Cdr stats service not configured"),
					})
					continue
				}
				rpfKey := utils.ConcatenatedKey(ratingProfileSearchKey, supplier)
				if rpf, err := ratingStorage.GetRatingProfile(rpfKey, false); err != nil {
					lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
						Supplier: fullSupplier,
						Error:    fmt.Sprintf("Rating plan error: %s", err.Error()),
					})
					continue
				} else if rpf != nil {
					rpf.RatingPlanActivations.Sort()
					activeRas := rpf.RatingPlanActivations.GetActiveForCall(cd)
					var cdrStatsQueueIds []string
					for _, ra := range activeRas {
						for _, qId := range ra.CdrStatQueueIds {
							if qId != "" {
								cdrStatsQueueIds = append(cdrStatsQueueIds, qId)
							}
						}
					}

					statsErr := false
					var supplierQueues []*StatsQueue
					for _, qId := range cdrStatsQueueIds {
						if lcrCost.Entry.Strategy == LCR_STRATEGY_LOAD {
							for _, qId := range cdrStatsQueueIds {
								sq := &StatsQueue{}
								if err := stats.GetQueue(qId, sq); err == nil {
									if sq.conf.QueueLength == 0 { //only add qeues that don't have fixed length
										supplierQueues = append(supplierQueues, sq)
									}
								}
							}
						} else {
							statValues := make(map[string]float64)
							if err := stats.GetValues(qId, &statValues); err != nil {
								lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
									Supplier: fullSupplier,
									Error:    fmt.Sprintf("Get stats values for queue id %s, error %s", qId, err.Error()),
								})
								statsErr = true
								break
							}
							if asr, exists := statValues[ASR]; exists {
								if asr > STATS_NA {
									asrValues = append(asrValues, asr)
								}
								asrNeverConsidered = false
							}
							if pdd, exists := statValues[PDD]; exists {
								if pdd > STATS_NA {
									pddValues = append(pddValues, pdd)
								}
								pddNeverConsidered = false
							}
							if acd, exists := statValues[ACD]; exists {
								if acd > STATS_NA {
									acdValues = append(acdValues, acd)
								}
								acdNeverConsidered = false
							}
							if tcd, exists := statValues[TCD]; exists {
								if tcd > STATS_NA {
									tcdValues = append(tcdValues, tcd)
								}
								tcdNeverConsidered = false
							}
							if acc, exists := statValues[ACC]; exists {
								if acc > STATS_NA {
									accValues = append(accValues, acc)
								}
								accNeverConsidered = false
							}
							if tcc, exists := statValues[TCC]; exists {
								if tcc > STATS_NA {
									tccValues = append(tccValues, tcc)
								}
								tccNeverConsidered = false
							}
							if ddc, exists := statValues[TCC]; exists {
								if ddc > STATS_NA {
									ddcValues = append(ddcValues, ddc)
								}
								ddcNeverConsidered = false
							}

						}
					}
					if lcrCost.Entry.Strategy == LCR_STRATEGY_LOAD {
						if len(supplierQueues) > 0 {
							lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
								Supplier:       fullSupplier,
								supplierQueues: supplierQueues,
							})
						}
						continue // next supplier
					}

					if statsErr { // Stats error in loop, to go next supplier
						continue
					}
					asrValues.Sort()
					pddValues.Sort()
					acdValues.Sort()
					tcdValues.Sort()
					accValues.Sort()
					tccValues.Sort()
					ddcValues.Sort()

					//log.Print(asrValues, acdValues)
					if utils.IsSliceMember([]string{LCR_STRATEGY_QOS_THRESHOLD, LCR_STRATEGY_QOS}, lcrCost.Entry.Strategy) {
						qosSortParams = lcrCost.Entry.GetParams()
					}
					if lcrCost.Entry.Strategy == LCR_STRATEGY_QOS_THRESHOLD {
						// filter suppliers by qos thresholds
						asrMin, asrMax, pddMin, pddMax, acdMin, acdMax, tcdMin, tcdMax, accMin, accMax, tccMin, tccMax, ddcMin, ddcMax := lcrCost.Entry.GetQOSLimits()
						//log.Print(asrMin, asrMax, acdMin, acdMax)
						// skip current supplier if off limits
						if asrMin > 0 && len(asrValues) != 0 && asrValues[0] < asrMin {
							continue
						}
						if asrMax > 0 && len(asrValues) != 0 && asrValues[len(asrValues)-1] > asrMax {
							continue
						}
						if pddMin > 0 && len(pddValues) != 0 && pddValues[0] < pddMin.Seconds() {
							continue
						}
						if pddMax > 0 && len(pddValues) != 0 && pddValues[len(pddValues)-1] > pddMax.Seconds() {
							continue
						}
						if acdMin > 0 && len(acdValues) != 0 && acdValues[0] < acdMin.Seconds() {
							continue
						}
						if acdMax > 0 && len(acdValues) != 0 && acdValues[len(acdValues)-1] > acdMax.Seconds() {
							continue
						}
						if tcdMin > 0 && len(tcdValues) != 0 && tcdValues[0] < tcdMin.Seconds() {
							continue
						}
						if tcdMax > 0 && len(tcdValues) != 0 && tcdValues[len(tcdValues)-1] > tcdMax.Seconds() {
							continue
						}
						if accMin > 0 && len(accValues) != 0 && accValues[0] < accMin {
							continue
						}
						if accMax > 0 && len(accValues) != 0 && accValues[len(accValues)-1] > accMax {
							continue
						}
						if tccMin > 0 && len(tccValues) != 0 && tccValues[0] < tccMin {
							continue
						}
						if tccMax > 0 && len(tccValues) != 0 && tccValues[len(tccValues)-1] > tccMax {
							continue
						}
						if ddcMin > 0 && len(ddcValues) != 0 && ddcValues[0] < ddcMin {
							continue
						}
						if ddcMax > 0 && len(ddcValues) != 0 && ddcValues[len(ddcValues)-1] > ddcMax {
							continue
						}
					}
				}
			}

			var cc *CallCost
			var err error
			//log.Print("CD: ", lcrCD.GetAccountKey())
			if cd.account, err = accountingStorage.GetAccount(lcrCD.GetAccountKey()); err == nil {
				//log.Print("ACCCOUNT")
				if cd.account.Disabled {
					lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
						Supplier: fullSupplier,
						Error:    fmt.Sprintf("supplier %s is disabled", supplier),
					})
					continue
				}
				cc, err = lcrCD.debit(cd.account, true, true)
			} else {
				//log.Print("STANDARD")
				cc, err = lcrCD.GetCost()
			}
			//log.Printf("CC: %+v", cc)
			if err != nil || cc == nil {
				lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
					Supplier: fullSupplier,
					Error:    err.Error(),
				})
				continue
			} else {
				supplCost := &LCRSupplierCost{
					Supplier: fullSupplier,
					Cost:     cc.Cost,
					Duration: cc.GetDuration(),
				}
				qos := make(map[string]float64, 5)
				if !asrNeverConsidered {
					qos[ASR] = utils.AvgNegative(asrValues)
				}
				if !pddNeverConsidered {
					qos[PDD] = utils.AvgNegative(pddValues)
				}
				if !acdNeverConsidered {
					qos[ACD] = utils.AvgNegative(acdValues)
				}
				if !tcdNeverConsidered {
					qos[TCD] = utils.AvgNegative(tcdValues)
				}
				if !accNeverConsidered {
					qos[ACC] = utils.AvgNegative(accValues)
				}
				if !tccNeverConsidered {
					qos[TCC] = utils.AvgNegative(tccValues)
				}
				if !ddcNeverConsidered {
					qos[DDC] = utils.AvgNegative(ddcValues)
				}
				if utils.IsSliceMember([]string{LCR_STRATEGY_QOS, LCR_STRATEGY_QOS_THRESHOLD}, lcrCost.Entry.Strategy) {
					supplCost.QOS = qos
					supplCost.qosSortParams = qosSortParams
				}
				lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, supplCost)
			}
		}
		// sort according to strategy
		lcrCost.Sort()
	}
	if p != nil {
		if p.Offset != nil && *p.Offset > 0 && *p.Offset < len(lcrCost.SupplierCosts) {
			lcrCost.SupplierCosts = lcrCost.SupplierCosts[*p.Offset:]
		}
		if p.Limit != nil && *p.Limit > 0 && *p.Limit < len(lcrCost.SupplierCosts) {
			lcrCost.SupplierCosts = lcrCost.SupplierCosts[:*p.Limit]
		}
	}
	return lcrCost, nil
}
예제 #4
0
func (cd *CallDescriptor) GetLCR() (*LCRCost, error) {
	lcr, err := dataStorage.GetLCR(cd.GetLCRKey(""), false)
	if err != nil || lcr == nil {
		// try the *any customer
		if lcr, err = dataStorage.GetLCR(cd.GetLCRKey(utils.ANY), false); err != nil || lcr == nil {
			return nil, err
		}
	}
	lcr.Sort()
	lcrCost := &LCRCost{
		TimeSpans: []*LCRTimeSpan{&LCRTimeSpan{StartTime: cd.TimeStart}},
	}
	for _, lcrActivation := range lcr.Activations {
		// TODO: filer entry by destination
		lcrEntry := lcrActivation.GetLCREntryForPrefix(cd.Destination)
		if lcrActivation.ActivationTime.Before(cd.TimeStart) ||
			lcrActivation.ActivationTime.Equal(cd.TimeStart) {
			lcrCost.TimeSpans[0].Entry = lcrEntry
		} else {
			if lcrActivation.ActivationTime.Before(cd.TimeEnd) {
				// add lcr timespan
				lcrCost.TimeSpans = append(lcrCost.TimeSpans, &LCRTimeSpan{
					StartTime: lcrActivation.ActivationTime,
					Entry:     lcrEntry,
				})
			}
		}
	}
	for _, ts := range lcrCost.TimeSpans {
		if ts.Entry.Strategy == LCR_STRATEGY_STATIC {
			for _, supplier := range strings.Split(ts.Entry.Suppliers, ";") {
				supplier = strings.TrimSpace(supplier)
				lcrCD := cd.Clone()
				lcrCD.Subject = supplier
				if cc, err := lcrCD.GetCost(); err != nil || cc == nil {
					ts.SupplierCosts = append(ts.SupplierCosts, &LCRSupplierCost{
						Supplier: supplier,
						Error:    err,
					})
				} else {
					ts.SupplierCosts = append(ts.SupplierCosts, &LCRSupplierCost{
						Supplier: supplier,
						Cost:     cc.Cost,
					})
				}
			}
		} else {
			// find rating profiles
			ratingProfileSearchKey := fmt.Sprintf("%s:%s:%s:", lcr.Direction, lcr.Tenant, ts.Entry.Category)
			suppliers := cache2go.GetEntriesKeys(LCR_PREFIX + ratingProfileSearchKey)
			for _, supplier := range suppliers {
				split := strings.Split(supplier, ":")
				supplier = split[len(split)-1]
				lcrCD := cd.Clone()
				lcrCD.Subject = supplier
				if cc, err := lcrCD.GetCost(); err != nil || cc == nil {
					ts.SupplierCosts = append(ts.SupplierCosts, &LCRSupplierCost{
						Supplier: supplier,
						Error:    err,
					})
				} else {
					ts.SupplierCosts = append(ts.SupplierCosts, &LCRSupplierCost{
						Supplier: supplier,
						Cost:     cc.Cost,
					})
				}
			}
			// sort according to strategy
			ts.Sort()
		}
	}
	return lcrCost, nil
}
예제 #5
0
// Index cached ResourceLimits with MetaString filter types
func (rls *ResourceLimiterService) indexStringFilters(rlIDs []string) error {
	utils.Logger.Info("<RLs> Start indexing string filters")
	newStringIndexes := make(map[string]map[string]utils.StringMap) // Index it transactional
	var cacheIDsToIndex []string                                    // Cache keys of RLs to be indexed
	if rlIDs == nil {
		cacheIDsToIndex = cache2go.GetEntriesKeys(utils.ResourceLimitsPrefix)
	} else {
		for _, rlID := range rlIDs {
			cacheIDsToIndex = append(cacheIDsToIndex, utils.ResourceLimitsPrefix+rlID)
		}
	}
	for _, cacheKey := range cacheIDsToIndex {
		x, ok := cache2go.Get(cacheKey)
		if !ok {
			return utils.ErrNotFound
		}
		rl := x.(*ResourceLimit)
		var hasMetaString bool
		for _, fltr := range rl.Filters {
			if fltr.Type != MetaString {
				continue
			}
			hasMetaString = true // Mark that we found at least one metatring so we don't need to index globally
			if _, hastIt := newStringIndexes[fltr.FieldName]; !hastIt {
				newStringIndexes[fltr.FieldName] = make(map[string]utils.StringMap)
			}
			for _, fldVal := range fltr.Values {
				if _, hasIt := newStringIndexes[fltr.FieldName][fldVal]; !hasIt {
					newStringIndexes[fltr.FieldName][fldVal] = make(utils.StringMap)
				}
				newStringIndexes[fltr.FieldName][fldVal][rl.ID] = true
			}
		}
		if !hasMetaString {
			if _, hasIt := newStringIndexes[utils.NOT_AVAILABLE]; !hasIt {
				newStringIndexes[utils.NOT_AVAILABLE] = make(map[string]utils.StringMap)
			}
			if _, hasIt := newStringIndexes[utils.NOT_AVAILABLE][utils.NOT_AVAILABLE]; !hasIt {
				newStringIndexes[utils.NOT_AVAILABLE][utils.NOT_AVAILABLE] = make(utils.StringMap)
			}
			newStringIndexes[utils.NOT_AVAILABLE][utils.NOT_AVAILABLE][rl.ID] = true // Fields without real field index will be located in map[NOT_AVAILABLE][NOT_AVAILABLE][rl.ID]
		}
	}
	rls.Lock()
	defer rls.Unlock()
	if rlIDs == nil { // We have rebuilt complete index
		rls.stringIndexes = newStringIndexes
		return nil
	}
	// Merge the indexes since we have only performed limited indexing
	for fldNameKey, mpFldName := range newStringIndexes {
		if _, hasIt := rls.stringIndexes[fldNameKey]; !hasIt {
			rls.stringIndexes[fldNameKey] = mpFldName
		} else {
			for fldValKey, strMap := range newStringIndexes[fldNameKey] {
				if _, hasIt := rls.stringIndexes[fldNameKey][fldValKey]; !hasIt {
					rls.stringIndexes[fldNameKey][fldValKey] = strMap
				} else {
					for resIDKey := range newStringIndexes[fldNameKey][fldValKey] {
						rls.stringIndexes[fldNameKey][fldValKey][resIDKey] = true
					}
				}
			}
		}
	}
	utils.Logger.Info("<RLs> Done indexing string filters")
	return nil
}