Merge branch 'master' into hapool

This commit is contained in:
Radu Ioan Fericean
2015-08-18 20:18:01 +03:00
41 changed files with 947 additions and 509 deletions

View File

@@ -486,7 +486,7 @@ func mailAsync(ub *Account, sq *StatsQueueTriggered, a *Action, acs Actions) err
message = []byte(fmt.Sprintf("To: %s\r\nSubject: [CGR Notification] Threshold hit on Balance: %s\r\n\r\nTime: \r\n\t%s\r\n\r\nBalance:\r\n\t%s\r\n\r\nYours faithfully,\r\nCGR Balance Monitor\r\n", toAddrStr, ub.Id, time.Now(), balJsn))
} else if sq != nil {
message = []byte(fmt.Sprintf("To: %s\r\nSubject: [CGR Notification] Threshold hit on StatsQueueId: %s\r\n\r\nTime: \r\n\t%s\r\n\r\nStatsQueueId:\r\n\t%s\r\n\r\nMetrics:\r\n\t%+v\r\n\r\nTrigger:\r\n\t%+v\r\n\r\nYours faithfully,\r\nCGR CDR Stats Monitor\r\n",
toAddrStr, sq.Id, time.Now(), sq.Id, sq.metrics, sq.Trigger))
toAddrStr, sq.Id, time.Now(), sq.Id, sq.Metrics, sq.Trigger))
}
auth := smtp.PlainAuth("", cgrCfg.MailerAuthUser, cgrCfg.MailerAuthPass, strings.Split(cgrCfg.MailerServer, ":")[0]) // We only need host part, so ignore port
go func() {

View File

@@ -349,22 +349,6 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
}
}
}
// split on days
/*for i := 0; i < len(timespans); i++ {
if timespans[i].TimeStart.Day() != timespans[i].TimeEnd.Day() {
//log.Print("TS: ", timespans[i].TimeStart, timespans[i].TimeEnd)
start := timespans[i].TimeStart
newTs := timespans[i].SplitByTime(time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()).Add(24 * time.Hour))
if newTs != nil {
//log.Print("NEW TS: ", newTs.TimeStart, newTs.TimeEnd)
// insert the new timespan
index := i + 1
timespans = append(timespans, nil)
copy(timespans[index+1:], timespans[index:])
timespans[index] = newTs
}
}
}*/
// Logger.Debug(fmt.Sprintf("After SplitByRatingPlan: %+v", timespans))
// split on rate intervals
for i := 0; i < len(timespans); i++ {
@@ -796,7 +780,7 @@ func (cd *CallDescriptor) GetLCRFromStorage() (*LCR, error) {
return nil, utils.ErrNotFound
}
func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
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 {
@@ -832,12 +816,13 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
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: supplier,
Supplier: fullSupplier,
Error: fmt.Sprintf("supplier %s is disabled", supplier),
})
continue
@@ -847,16 +832,15 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
cc, err = lcrCD.GetCost()
}
supplier = utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
//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: supplier,
Supplier: fullSupplier,
Error: err.Error(),
})
} else {
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
Cost: cc.Cost,
Duration: cc.GetDuration(),
})
@@ -879,6 +863,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
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
@@ -898,7 +883,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
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: supplier,
Supplier: fullSupplier,
Error: fmt.Sprintf("Cdr stats service not configured"),
})
continue
@@ -906,7 +891,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
rpfKey := utils.ConcatenatedKey(ratingProfileSearchKey, supplier)
if rpf, err := ratingStorage.GetRatingProfile(rpfKey, false); err != nil {
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
Error: fmt.Sprintf("Rating plan error: %s", err.Error()),
})
continue
@@ -938,7 +923,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
statValues := make(map[string]float64)
if err := stats.GetValues(qId, &statValues); err != nil {
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
Error: fmt.Sprintf("Get stats values for queue id %s, error %s", qId, err.Error()),
})
statsErr = true
@@ -992,7 +977,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
if lcrCost.Entry.Strategy == LCR_STRATEGY_LOAD {
if len(supplierQueues) > 0 {
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
supplierQueues: supplierQueues,
})
}
@@ -1072,7 +1057,7 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
//log.Print("ACCCOUNT")
if cd.account.Disabled {
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
Error: fmt.Sprintf("supplier %s is disabled", supplier),
})
continue
@@ -1083,16 +1068,15 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
cc, err = lcrCD.GetCost()
}
//log.Printf("CC: %+v", cc)
supplier = utils.ConcatenatedKey(lcrCD.Direction, lcrCD.Tenant, lcrCD.Category, lcrCD.Subject)
if err != nil || cc == nil {
lcrCost.SupplierCosts = append(lcrCost.SupplierCosts, &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
Error: err.Error(),
})
continue
} else {
supplCost := &LCRSupplierCost{
Supplier: supplier,
Supplier: fullSupplier,
Cost: cc.Cost,
Duration: cc.GetDuration(),
}
@@ -1128,5 +1112,13 @@ func (cd *CallDescriptor) GetLCR(stats StatsInterface) (*LCRCost, error) {
// 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
}

View File

@@ -48,14 +48,16 @@ const (
// A request for LCR, used in APIer and SM where we need to expose it
type LcrRequest struct {
Direction string
Tenant string
Category string
Account string
Subject string
Destination string
StartTime string
Duration string
Direction string
Tenant string
Category string
Account string
Subject string
Destination string
SetupTime string
Duration string
IgnoreErrors bool
*utils.Paginator
}
func (self *LcrRequest) AsCallDescriptor() (*CallDescriptor, error) {
@@ -77,9 +79,9 @@ func (self *LcrRequest) AsCallDescriptor() (*CallDescriptor, error) {
}
var timeStart time.Time
var err error
if len(self.StartTime) == 0 {
if len(self.SetupTime) == 0 {
timeStart = time.Now()
} else if timeStart, err = utils.ParseTimeDetectLayout(self.StartTime); err != nil {
} else if timeStart, err = utils.ParseTimeDetectLayout(self.SetupTime); err != nil {
return nil, err
}
var callDur time.Duration
@@ -433,6 +435,9 @@ func (lc *LCRCost) SuppliersSlice() ([]string, error) {
}
supps := []string{}
for _, supplCost := range lc.SupplierCosts {
if supplCost.Error != "" {
continue // Do not add the supplier with cost errors to list of suppliers available
}
if dtcs, err := utils.NewDTCSFromRPKey(supplCost.Supplier); err != nil {
return nil, err
} else if len(dtcs.Subject) != 0 {

View File

@@ -204,7 +204,7 @@ func TestLcrGet(t *testing.T) {
Account: "rif",
Subject: "rif",
}
lcr, err := cd.GetLCR(nil)
lcr, err := cd.GetLCR(nil, nil)
//jsn, _ := json.Marshal(lcr)
//log.Print("LCR: ", string(jsn))
if err != nil || lcr == nil {
@@ -215,11 +215,11 @@ func TestLcrGet(t *testing.T) {
func TestLcrRequestAsCallDescriptor(t *testing.T) {
sTime := time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC)
callDur := time.Duration(1) * time.Minute
lcrReq := &LcrRequest{Account: "2001", StartTime: sTime.String()}
lcrReq := &LcrRequest{Account: "2001", SetupTime: sTime.String()}
if _, err := lcrReq.AsCallDescriptor(); err == nil || err != utils.ErrMandatoryIeMissing {
t.Error("Unexpected error received: %v", err)
}
lcrReq = &LcrRequest{Account: "2001", Destination: "2002", StartTime: sTime.String()}
lcrReq = &LcrRequest{Account: "2001", Destination: "2002", SetupTime: sTime.String()}
eCd := &CallDescriptor{
Direction: utils.OUT,
Tenant: config.CgrConfig().DefaultTenant,

View File

@@ -41,6 +41,11 @@ type SessionRun struct {
CallCosts []*CallCost
}
type AttrGetLcr struct {
*CallDescriptor
*utils.Paginator
}
type Responder struct {
Bal *balancer2go.Balancer
ExitChan chan bool
@@ -386,20 +391,25 @@ func (rs *Responder) LogCallCost(ccl *CallCostLog, reply *string) error {
return nil
}
func (rs *Responder) GetLCR(cd *CallDescriptor, reply *LCRCost) error {
if cd.Subject == "" {
cd.Subject = cd.Account
func (rs *Responder) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error {
if attrs.CallDescriptor.Subject == "" {
attrs.CallDescriptor.Subject = attrs.CallDescriptor.Account
}
if upData, err := LoadUserProfile(cd, "ExtraFields"); err != nil {
if upData, err := LoadUserProfile(attrs.CallDescriptor, "ExtraFields"); err != nil {
return err
} else {
udRcv := upData.(*CallDescriptor)
*cd = *udRcv
*attrs.CallDescriptor = *udRcv
}
lcrCost, err := cd.GetLCR(rs.Stats)
lcrCost, err := attrs.CallDescriptor.GetLCR(rs.Stats, attrs.Paginator)
if err != nil {
return err
}
if lcrCost.Entry.Strategy == LCR_STRATEGY_LOAD {
for _, suppl := range lcrCost.SupplierCosts {
suppl.Cost = -1 // In case of load distribution we don't calculate costs
}
}
*reply = *lcrCost
return nil
}
@@ -570,7 +580,7 @@ type Connector interface {
GetSessionRuns(*StoredCdr, *[]*SessionRun) error
ProcessCdr(*StoredCdr, *string) error
LogCallCost(*CallCostLog, *string) error
GetLCR(*CallDescriptor, *LCRCost) error
GetLCR(*AttrGetLcr, *LCRCost) error
GetTimeout() time.Duration
}
@@ -619,8 +629,8 @@ func (rcc *RPCClientConnector) LogCallCost(ccl *CallCostLog, reply *string) erro
return rcc.Client.Call("CDRSV1.LogCallCost", ccl, reply)
}
func (rcc *RPCClientConnector) GetLCR(cd *CallDescriptor, reply *LCRCost) error {
return rcc.Client.Call("Responder.GetLCR", cd, reply)
func (rcc *RPCClientConnector) GetLCR(attrs *AttrGetLcr, reply *LCRCost) error {
return rcc.Client.Call("Responder.GetLCR", attrs, reply)
}
func (rcc *RPCClientConnector) GetTimeout() time.Duration {

View File

@@ -395,7 +395,7 @@ func TestGetLCR(t *testing.T) {
},
}
var lcr LCRCost
if err := rsponder.GetLCR(cdStatic, &lcr); err != nil {
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdStatic}, &lcr); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eStLcr.Entry, lcr.Entry) {
t.Errorf("Expecting: %+v, received: %+v", eStLcr.Entry, lcr.Entry)
@@ -422,7 +422,7 @@ func TestGetLCR(t *testing.T) {
},
}
var lcrLc LCRCost
if err := rsponder.GetLCR(cdLowestCost, &lcrLc); err != nil {
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdLowestCost}, &lcrLc); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eLcLcr.Entry, lcrLc.Entry) {
t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry)
@@ -447,7 +447,7 @@ func TestGetLCR(t *testing.T) {
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second},
},
}
if err := rsponder.GetLCR(cdLowestCost, &lcrLc); err != nil {
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdLowestCost}, &lcrLc); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eLcLcr.Entry, lcrLc.Entry) {
t.Errorf("Expecting: %+v, received: %+v", eLcLcr.Entry, lcrLc.Entry)
@@ -476,7 +476,7 @@ func TestGetLCR(t *testing.T) {
},
}
var lcrQT LCRCost
if err := rsponder.GetLCR(cdQosThreshold, &lcrQT); err != nil {
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) {
t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry)
@@ -495,7 +495,7 @@ func TestGetLCR(t *testing.T) {
&LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second, QOS: map[string]float64{PDD: -1, ACD: 300, TCD: 300, ASR: 100, ACC: 2, TCC: 2, DDC: 2}, qosSortParams: []string{"35", "4m"}},
},
}
if err := rsponder.GetLCR(cdQosThreshold, &lcrQT); err != nil {
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQosThreshold}, &lcrQT); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eQTLcr.Entry, lcrQT.Entry) {
t.Errorf("Expecting: %+v, received: %+v", eQTLcr.Entry, lcrQT.Entry)
@@ -524,7 +524,7 @@ func TestGetLCR(t *testing.T) {
},
}
var lcrQ LCRCost
if err := rsponder.GetLCR(cdQos, &lcrQ); err != nil {
if err := rsponder.GetLCR(&AttrGetLcr{CallDescriptor: cdQos}, &lcrQ); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eQosLcr.Entry, lcrQ.Entry) {
t.Errorf("Expecting: %+v, received: %+v", eQosLcr.Entry, lcrQ.Entry)

View File

@@ -215,12 +215,12 @@ func (sq *StatsQueue) GetId() string {
// Convert data into a struct which can be used in actions based on triggers hit
func (sq *StatsQueue) Triggered(at *ActionTrigger) *StatsQueueTriggered {
return &StatsQueueTriggered{Id: sq.conf.Id, metrics: sq.getStats(), Trigger: at}
return &StatsQueueTriggered{Id: sq.conf.Id, Metrics: sq.getStats(), Trigger: at}
}
// Struct to be passed to triggered actions
type StatsQueueTriggered struct {
Id string // StatsQueueId
metrics map[string]float64
Metrics map[string]float64
Trigger *ActionTrigger
}

View File

@@ -416,22 +416,6 @@ func (ts *TimeSpan) SplitByRateInterval(i *RateInterval, data bool) (nts *TimeSp
return
}
/*func (ts *TimeSpan) SplitByTime(splitTime time.Time) (nts *TimeSpan) {
if splitTime.Equal(ts.TimeEnd) {
return
}
nts = &TimeSpan{
TimeStart: splitTime,
TimeEnd: ts.TimeEnd,
}
nts.copyRatingInfo(ts)
ts.TimeEnd = splitTime
nts.SetRateInterval(ts.RateInterval)
nts.DurationIndex = ts.DurationIndex
ts.SetNewDurationIndex(nts)
return
}*/
// Split the timespan at the given increment start
func (ts *TimeSpan) SplitByIncrement(index int) *TimeSpan {
if index <= 0 || index >= len(ts.Increments) {