diff --git a/agents/agentreq.go b/agents/agentreq.go
index 718c7df3b..b63d6b72e 100644
--- a/agents/agentreq.go
+++ b/agents/agentreq.go
@@ -151,6 +151,23 @@ func (aReq *AgentRequest) ParseField(
case utils.META_COMPOSED:
out = aReq.composedField(cfgFld.Value)
isString = true
+ case utils.META_USAGE_DIFFERENCE:
+ if len(cfgFld.Value) != 2 {
+ return nil, fmt.Errorf("invalid arguments <%s>", utils.ToJSON(cfgFld.Value))
+ } else {
+ strVal1, err := aReq.FieldAsString(strings.Split(cfgFld.Value[0].Id, utils.NestingSep))
+ strVal2, err := aReq.FieldAsString(strings.Split(cfgFld.Value[1].Id, utils.NestingSep))
+ tEnd, err := utils.ParseTimeDetectLayout(strVal1, cfgFld.Timezone)
+ if err != nil {
+ return "", err
+ }
+ tStart, err := utils.ParseTimeDetectLayout(strVal2, cfgFld.Timezone)
+ if err != nil {
+ return "", err
+ }
+ out = tEnd.Sub(tStart).String()
+ }
+ isString = true
}
if isString { // format the string additionally with fmtFieldWidth
out, err = utils.FmtFieldWidth(cfgFld.Tag, out.(string), cfgFld.Width,
@@ -172,17 +189,18 @@ func (ar *AgentRequest) composedField(outTpl utils.RSRFields) (outVal string) {
}
continue
}
+
valStr, err := ar.FieldAsString(strings.Split(rsrTpl.Id, utils.NestingSep))
if err != nil {
utils.Logger.Warning(
- fmt.Sprintf("<%s> %s",
- utils.HTTPAgent, err.Error()))
+ fmt.Sprintf("<%s> %s FieldAsString %s",
+ utils.AgentRequest, err.Error(), rsrTpl.Id))
continue
}
if parsed, err := rsrTpl.Parse(valStr); err != nil {
utils.Logger.Warning(
- fmt.Sprintf("<%s> %s",
- utils.HTTPAgent, err.Error()))
+ fmt.Sprintf("<%s> %s Parse ",
+ utils.AgentRequest, err.Error(), valStr))
} else {
outVal += parsed
}
diff --git a/agents/agentreq_test.go b/agents/agentreq_test.go
index 8c859a2c0..4e3a7de9e 100644
--- a/agents/agentreq_test.go
+++ b/agents/agentreq_test.go
@@ -18,7 +18,6 @@ along with this program. If not, see
package agents
-/*
import (
"reflect"
"testing"
@@ -121,8 +120,6 @@ func TestAgReqAsNavigableMap(t *testing.T) {
if mpOut, err := agReq.AsNavigableMap(tplFlds); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eMp, mpOut) {
- t.Errorf("expecting: %+v, received: %+v",
- eMp.AsMapStringInterface(), mpOut.AsMapStringInterface())
+ t.Errorf("expecting: %+v, received: %+v", eMp, mpOut)
}
}
-*/
diff --git a/agents/libdmt.go b/agents/libdmt.go
index 57ab7929d..7c21935b0 100644
--- a/agents/libdmt.go
+++ b/agents/libdmt.go
@@ -64,6 +64,153 @@ var (
ErrDiameterRatingFailed = errors.New("Diameter rating failed")
)
+// processorVars will hold various variables using during request processing
+// here so we can define methods on it
+type processorVars map[string]interface{}
+
+// hasSubsystems will return true on single subsystem being present in processorVars
+func (pv processorVars) hasSubsystems() (has bool) {
+ for _, k := range []string{utils.MetaAccounts, utils.MetaResources,
+ utils.MetaSuppliers, utils.MetaAttributes} {
+ if _, has = pv[k]; has {
+ return
+ }
+ }
+ return
+}
+
+func (pv processorVars) hasVar(k string) (has bool) {
+ _, has = pv[k]
+ return
+}
+
+// valAsInterface returns the string value for fldName
+func (pv processorVars) valAsInterface(fldPath string) (val interface{}, err error) {
+ fldName := fldPath
+ if strings.HasPrefix(fldPath, utils.MetaCGRReply) {
+ fldName = utils.MetaCGRReply
+ }
+ if !pv.hasVar(fldName) {
+ err = errors.New("not found")
+ return
+ }
+ return engine.NewNavigableMap(pv).FieldAsInterface(strings.Split(fldPath, utils.HIERARCHY_SEP))
+}
+
+// valAsString returns the string value for fldName
+// returns empty if fldName not found
+func (pv processorVars) valAsString(fldPath string) (val string, err error) {
+ fldName := fldPath
+ if strings.HasPrefix(fldPath, utils.MetaCGRReply) {
+ fldName = utils.MetaCGRReply
+ }
+ if !pv.hasVar(fldName) {
+ return "", utils.ErrNotFoundNoCaps
+ }
+ return engine.NewNavigableMap(pv).FieldAsString(strings.Split(fldPath, utils.HIERARCHY_SEP))
+}
+
+// asV1AuthorizeArgs returns the arguments needed by SessionSv1.AuthorizeEvent
+func (pv processorVars) asV1AuthorizeArgs(cgrEv *utils.CGREvent) (args *sessions.V1AuthorizeArgs) {
+ args = &sessions.V1AuthorizeArgs{ // defaults
+ GetMaxUsage: true,
+ CGREvent: *cgrEv,
+ }
+ if !pv.hasSubsystems() {
+ return
+ }
+ if !pv.hasVar(utils.MetaAccounts) {
+ args.GetMaxUsage = false
+ }
+ if pv.hasVar(utils.MetaResources) {
+ args.AuthorizeResources = true
+ }
+ if pv.hasVar(utils.MetaSuppliers) {
+ args.GetSuppliers = true
+ }
+ if pv.hasVar(utils.MetaAttributes) {
+ args.GetAttributes = true
+ }
+ return
+}
+
+// asV1InitSessionArgs returns the arguments used in SessionSv1.InitSession
+func (pv processorVars) asV1InitSessionArgs(cgrEv *utils.CGREvent) (args *sessions.V1InitSessionArgs) {
+ args = &sessions.V1InitSessionArgs{ // defaults
+ InitSession: true,
+ CGREvent: *cgrEv,
+ }
+ if !pv.hasSubsystems() {
+ return
+ }
+ if !pv.hasVar(utils.MetaAccounts) {
+ args.InitSession = false
+ }
+ if pv.hasVar(utils.MetaResources) {
+ args.AllocateResources = true
+ }
+ if pv.hasVar(utils.MetaAttributes) {
+ args.GetAttributes = true
+ }
+ return
+}
+
+// asV1UpdateSessionArgs returns the arguments used in SessionSv1.InitSession
+func (pv processorVars) asV1UpdateSessionArgs(cgrEv *utils.CGREvent) (args *sessions.V1UpdateSessionArgs) {
+ args = &sessions.V1UpdateSessionArgs{ // defaults
+ UpdateSession: true,
+ CGREvent: *cgrEv,
+ }
+ if !pv.hasSubsystems() {
+ return
+ }
+ if !pv.hasVar(utils.MetaAccounts) {
+ args.UpdateSession = false
+ }
+ if pv.hasVar(utils.MetaAttributes) {
+ args.GetAttributes = true
+ }
+ return
+}
+
+// asV1TerminateSessionArgs returns the arguments used in SMGv1.TerminateSession
+func (pv processorVars) asV1TerminateSessionArgs(cgrEv *utils.CGREvent) (args *sessions.V1TerminateSessionArgs) {
+ args = &sessions.V1TerminateSessionArgs{ // defaults
+ TerminateSession: true,
+ CGREvent: *cgrEv,
+ }
+ if !pv.hasSubsystems() {
+ return
+ }
+ if !pv.hasVar(utils.MetaAccounts) {
+ args.TerminateSession = false
+ }
+ if pv.hasVar(utils.MetaResources) {
+ args.ReleaseResources = true
+ }
+ return
+}
+
+func (pv processorVars) asV1ProcessEventArgs(cgrEv *utils.CGREvent) (args *sessions.V1ProcessEventArgs) {
+ args = &sessions.V1ProcessEventArgs{ // defaults
+ Debit: true,
+ CGREvent: *cgrEv,
+ }
+ if !pv.hasSubsystems() {
+ return
+ }
+ if !pv.hasVar(utils.MetaAccounts) {
+ args.Debit = false
+ }
+ if pv.hasVar(utils.MetaResources) {
+ args.AllocateResources = true
+ }
+ if pv.hasVar(utils.MetaAttributes) {
+ args.GetAttributes = true
+ }
+ return
+}
+
func loadDictionaries(dictsDir, componentId string) error {
fi, err := os.Stat(dictsDir)
if err != nil {
diff --git a/agents/librad.go b/agents/librad.go
index d45daf455..ea55daf08 100644
--- a/agents/librad.go
+++ b/agents/librad.go
@@ -19,15 +19,11 @@ along with this program. If not, see
package agents
import (
- "errors"
"fmt"
- "strconv"
"strings"
- "time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/radigo"
)
@@ -47,7 +43,7 @@ func attrVendorFromPath(path string) (attrName, vendorName string) {
// radComposedFieldValue extracts the field value out of RADIUS packet
// procVars have priority over packet variables
func radComposedFieldValue(pkt *radigo.Packet,
- procVars processorVars, outTpl utils.RSRFields) (outVal string) {
+ agReq *AgentRequest, outTpl utils.RSRFields) (outVal string) {
for _, rsrTpl := range outTpl {
if rsrTpl.IsStatic() {
if parsed, err := rsrTpl.Parse(""); err != nil {
@@ -59,13 +55,11 @@ func radComposedFieldValue(pkt *radigo.Packet,
}
continue
}
- if val, err := procVars.valAsString(rsrTpl.Id); err != nil {
- if err.Error() != "not found" {
- utils.Logger.Warning(
- fmt.Sprintf("<%s> %s",
- utils.RadiusAgent, err.Error()))
- continue
- }
+ if val, err := agReq.FieldAsString(strings.Split(rsrTpl.Id, utils.NestingSep)); err != nil {
+ utils.Logger.Warning(
+ fmt.Sprintf("<%s> %s",
+ utils.RadiusAgent, err.Error()))
+ continue
} else {
if parsed, err := rsrTpl.Parse(val); err != nil {
utils.Logger.Warning(
@@ -90,41 +84,8 @@ func radComposedFieldValue(pkt *radigo.Packet,
return outVal
}
-// radMetaHandler handles *handler type in configuration fields
-func radMetaHandler(pkt *radigo.Packet, procVars processorVars,
- cfgFld *config.CfgCdrField, roundingDecimals int) (outVal string, err error) {
- handlerArgs := strings.Split(
- radComposedFieldValue(pkt, procVars, cfgFld.Value), utils.HandlerArgSep)
- switch cfgFld.HandlerId {
- case MetaUsageDifference: // expects tEnd|tStart in the composed val
- if len(handlerArgs) != 2 {
- return "", errors.New("unexpected number of arguments")
- }
- tEnd, err := utils.ParseTimeDetectLayout(handlerArgs[0], cfgFld.Timezone)
- if err != nil {
- return "", err
- }
- tStart, err := utils.ParseTimeDetectLayout(handlerArgs[1], cfgFld.Timezone)
- if err != nil {
- return "", err
- }
- return tEnd.Sub(tStart).String(), nil
- case utils.MetaDurationSeconds:
- if len(handlerArgs) != 1 {
- return "", errors.New("unexpected number of arguments")
- }
- val, err := utils.ParseDurationWithNanosecs(handlerArgs[0])
- if err != nil {
- return "", err
- }
- return strconv.FormatInt(int64(utils.Round(val.Seconds(),
- roundingDecimals, utils.ROUNDING_MIDDLE)), 10), nil
- }
- return
-}
-
// radFieldOutVal formats the field value retrieved from RADIUS packet
-func radFieldOutVal(pkt *radigo.Packet, processorVars processorVars,
+func radFieldOutVal(pkt *radigo.Packet, agReq *AgentRequest,
cfgFld *config.CfgCdrField) (outVal string, err error) {
// different output based on cgrFld.Type
switch cfgFld.Type {
@@ -134,12 +95,7 @@ func radFieldOutVal(pkt *radigo.Packet, processorVars processorVars,
case utils.META_CONSTANT:
outVal = cfgFld.Value.Id()
case utils.META_COMPOSED:
- outVal = radComposedFieldValue(pkt, processorVars, cfgFld.Value)
- case utils.META_HANDLER:
- if outVal, err = radMetaHandler(pkt, processorVars, cfgFld,
- config.CgrConfig().RoundingDecimals); err != nil {
- return "", err
- }
+ outVal = radComposedFieldValue(pkt, agReq, cfgFld.Value)
default:
return "", fmt.Errorf("unsupported configuration field type: <%s>", cfgFld.Type)
}
@@ -150,20 +106,10 @@ func radFieldOutVal(pkt *radigo.Packet, processorVars processorVars,
}
// radReplyAppendAttributes appends attributes to a RADIUS reply based on predefined template
-func radReplyAppendAttributes(reply *radigo.Packet, procVars map[string]interface{},
+func radReplyAppendAttributes(reply *radigo.Packet, agReq *AgentRequest,
cfgFlds []*config.CfgCdrField) (err error) {
for _, cfgFld := range cfgFlds {
- passedAllFilters := true
- for _, fldFilter := range cfgFld.FieldFilter {
- if !radPassesFieldFilter(reply, procVars, fldFilter) {
- passedAllFilters = false
- break
- }
- }
- if !passedAllFilters {
- continue
- }
- fmtOut, err := radFieldOutVal(reply, procVars, cfgFld)
+ fmtOut, err := radFieldOutVal(reply, agReq, cfgFld)
if err != nil {
return err
}
@@ -191,12 +137,15 @@ func NewCGRReply(rply engine.NavigableMapper,
return engine.NewNavigableMap(map[string]interface{}{
utils.Error: errRply.Error()}), nil
}
- mp, err = rply.AsNavigableMap(nil)
- if err != nil {
- return nil, err
+ mp = engine.NewNavigableMap(nil)
+ if rply != nil {
+ mp, err = rply.AsNavigableMap(nil)
+ if err != nil {
+ return nil, err
+ }
}
mp.Set([]string{utils.Error}, "", false) // enforce empty error
- return mp, nil
+ return
}
// newRADataProvider constructs a DataProvider
@@ -215,7 +164,7 @@ type radiusDP struct {
// String is part of engine.DataProvider interface
// when called, it will display the already parsed values out of cache
func (pk *radiusDP) String() string {
- return ""
+ return utils.ToJSON(pk)
}
// FieldAsInterface is part of engine.DataProvider interface
@@ -228,6 +177,9 @@ func (pk *radiusDP) FieldAsInterface(fldPath []string) (data interface{}, err er
return
}
err = nil // cancel previous err
+ if len(pk.req.AttributesWithName(fldPath[0], "")) != 0 {
+ data = pk.req.AttributesWithName(fldPath[0], "")[0].GetStringValue()
+ }
pk.cache.Set(fldPath, data, false)
return
}
diff --git a/agents/librad_test.go b/agents/librad_test.go
index 89d0b7ed3..8a89d98f9 100644
--- a/agents/librad_test.go
+++ b/agents/librad_test.go
@@ -28,7 +28,6 @@ import (
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
- "github.com/cgrates/cgrates/sessions"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/radigo"
)
@@ -91,47 +90,6 @@ func TestAttrVendorFromPath(t *testing.T) {
}
}
-func TestRadPassesFieldFilter(t *testing.T) {
- pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org")
- if err := pkt.AddAVPWithName("User-Name", "flopsy", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Cisco-NAS-Port", "CGR1", "Cisco"); err != nil {
- t.Error(err)
- }
- if !radPassesFieldFilter(pkt, nil, nil) {
- t.Error("not passing empty filter")
- }
- if !radPassesFieldFilter(pkt, nil,
- utils.NewRSRFieldMustCompile("User-Name(flopsy)")) {
- t.Error("not passing valid filter")
- }
- if radPassesFieldFilter(pkt, nil,
- utils.NewRSRFieldMustCompile("User-Name(notmatching)")) {
- t.Error("passing invalid filter value")
- }
- if !radPassesFieldFilter(pkt, nil,
- utils.NewRSRFieldMustCompile("Cisco>Cisco-NAS-Port(CGR1)")) {
- t.Error("not passing valid filter")
- }
- if radPassesFieldFilter(pkt, nil,
- utils.NewRSRFieldMustCompile("Cisco>Cisco-NAS-Port(notmatching)")) {
- t.Error("passing invalid filter value")
- }
- if !radPassesFieldFilter(pkt, processorVars{MetaRadReqType: MetaRadAuth},
- utils.NewRSRFieldMustCompile(fmt.Sprintf("%s(%s)", MetaRadReqType, MetaRadAuth))) {
- t.Error("not passing valid filter")
- }
- if radPassesFieldFilter(pkt, processorVars{MetaRadReqType: MetaRadAcctStart},
- utils.NewRSRFieldMustCompile(fmt.Sprintf("%s(%s)", MetaRadReqType, MetaRadAuth))) {
- t.Error("passing invalid filter")
- }
- if radPassesFieldFilter(pkt, nil,
- utils.NewRSRFieldMustCompile("UnknownField(notmatching)")) {
- t.Error("passing invalid filter value")
- }
-}
-
func TestRadComposedFieldValue(t *testing.T) {
pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org")
if err := pkt.AddAVPWithName("User-Name", "flopsy", ""); err != nil {
@@ -140,10 +98,13 @@ func TestRadComposedFieldValue(t *testing.T) {
if err := pkt.AddAVPWithName("Cisco-NAS-Port", "CGR1", "Cisco"); err != nil {
t.Error(err)
}
- eOut := fmt.Sprintf("%s|flopsy|CGR1", MetaRadAcctStart)
- if out := radComposedFieldValue(pkt, processorVars{MetaRadReqType: MetaRadAcctStart},
- utils.ParseRSRFieldsMustCompile(fmt.Sprintf("%s;^|;User-Name;^|;Cisco>Cisco-NAS-Port",
- MetaRadReqType), utils.INFIELD_SEP)); out != eOut {
+ agReq := newAgentRequest(nil, nil, "cgrates.org", nil)
+ agReq.Vars.Set([]string{MetaRadReqType}, MetaRadAcctStart, false)
+ agReq.Vars.Set([]string{"Cisco"}, "CGR1", false)
+ agReq.Vars.Set([]string{"User-Name"}, "flopsy", false)
+ eOut := "*radAcctStart|flopsy|CGR1"
+ if out := radComposedFieldValue(pkt, agReq,
+ utils.ParseRSRFieldsMustCompile("*vars.*radReqType;^|;*vars.User-Name;^|;*vars.Cisco", utils.INFIELD_SEP)); out != eOut {
t.Errorf("Expecting: <%s>, received: <%s>", eOut, out)
}
}
@@ -157,263 +118,33 @@ func TestRadFieldOutVal(t *testing.T) {
t.Error(err)
}
eOut := fmt.Sprintf("%s|flopsy|CGR1", MetaRadAcctStart)
+ agReq := newAgentRequest(nil, nil, "cgrates.org", nil)
+ agReq.Vars.Set([]string{MetaRadReqType}, MetaRadAcctStart, false)
+ agReq.Vars.Set([]string{"Cisco"}, "CGR1", false)
+ agReq.Vars.Set([]string{"User-Name"}, "flopsy", false)
+ //processorVars{MetaRadReqType: MetaRadAcctStart}
cfgFld := &config.CfgCdrField{Tag: "ComposedTest", Type: utils.META_COMPOSED, FieldId: utils.Destination,
- Value: utils.ParseRSRFieldsMustCompile(fmt.Sprintf("%s;^|;User-Name;^|;Cisco>Cisco-NAS-Port", MetaRadReqType), utils.INFIELD_SEP), Mandatory: true}
- if outVal, err := radFieldOutVal(pkt, processorVars{MetaRadReqType: MetaRadAcctStart}, cfgFld); err != nil {
+ Value: utils.ParseRSRFieldsMustCompile("*vars.*radReqType;^|;*vars.User-Name;^|;*vars.Cisco", utils.INFIELD_SEP), Mandatory: true}
+ if outVal, err := radFieldOutVal(pkt, agReq, cfgFld); err != nil {
t.Error(err)
} else if outVal != eOut {
t.Errorf("Expecting: <%s>, received: <%s>", eOut, outVal)
}
}
-func TestRadReqAsCGREvent(t *testing.T) {
- pkt := radigo.NewPacket(radigo.AccountingRequest, 1, dictRad, coder, "CGRateS.org")
- // Sample minimal packet sent by Kamailio
- if err := pkt.AddAVPWithName("Acct-Status-Type", "2", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Service-Type", "15", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Sip-Response-Code", "200", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Sip-Method", "8", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Event-Timestamp", "1497106119", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Sip-From-Tag", "75c2f57b", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Sip-To-Tag", "51585361", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Acct-Session-Id", "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("User-Name", "1001", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Called-Station-Id", "1002", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Ascend-User-Acct-Time", "1497106115", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("NAS-Port-Id", "5060", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("Acct-Delay-Time", "0", ""); err != nil {
- t.Error(err)
- }
- if err := pkt.AddAVPWithName("NAS-IP-Address", "127.0.0.1", ""); err != nil {
- t.Error(err)
- }
-
- cfgFlds := []*config.CfgCdrField{
- &config.CfgCdrField{Tag: "TOR", FieldId: utils.ToR, Type: utils.META_CONSTANT,
- Value: utils.ParseRSRFieldsMustCompile(utils.VOICE, utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "OriginID", FieldId: utils.OriginID, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("Acct-Session-Id;^-;Sip-From-Tag;^-;Sip-To-Tag", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "OriginHost", FieldId: utils.OriginHost, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("NAS-IP-Address", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "RequestType", FieldId: utils.RequestType, Type: utils.META_CONSTANT,
- Value: utils.ParseRSRFieldsMustCompile(utils.META_PREPAID, utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "Direction", FieldId: utils.Direction, Type: utils.META_CONSTANT,
- Value: utils.ParseRSRFieldsMustCompile(utils.OUT, utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "Tenant", FieldId: utils.Tenant, Type: utils.META_CONSTANT,
- Value: utils.ParseRSRFieldsMustCompile("cgrates.org", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "Category", FieldId: utils.Category, Type: utils.META_CONSTANT,
- Value: utils.ParseRSRFieldsMustCompile("call", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "Account", FieldId: utils.Account, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("User-Name", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "Destination", FieldId: utils.Destination, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("Called-Station-Id", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "SetupTime", FieldId: utils.SetupTime, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("Ascend-User-Acct-Time", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "AnswerTime", FieldId: utils.AnswerTime, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("Ascend-User-Acct-Time", utils.INFIELD_SEP)},
- &config.CfgCdrField{Tag: "Usage", FieldId: utils.Usage, Type: utils.META_HANDLER, HandlerId: MetaUsageDifference,
- Value: utils.ParseRSRFieldsMustCompile("Event-Timestamp;^|;Ascend-User-Acct-Time", utils.INFIELD_SEP)},
- }
- eOut := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: utils.UUIDSha1Prefix(),
- Time: utils.TimePointer(time.Now()),
- Event: map[string]interface{}{
- utils.Account: "1001",
- utils.AnswerTime: "1497106115",
- utils.Category: "call",
- utils.Destination: "1002",
- utils.Direction: utils.META_OUT,
- utils.OriginHost: "127.0.0.1",
- utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
- utils.RequestType: "*prepaid",
- utils.SetupTime: "1497106115",
- utils.Tenant: "cgrates.org",
- utils.ToR: "*voice",
- utils.Usage: "4s",
- },
- }
- if outVal, err := radReqAsCGREvent(pkt, processorVars{MetaRadReqType: MetaRadAcctStart}, nil, cfgFlds); err != nil {
- t.Error(err)
- } else if !reflect.DeepEqual(outVal.Tenant, eOut.Tenant) {
- t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(eOut.Tenant), utils.ToJSON(outVal.Tenant))
- } else if !reflect.DeepEqual(outVal.Event, eOut.Event) {
- t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(eOut.Event), utils.ToJSON(outVal.Event))
- }
-}
-
-func TestPVAsV1AuthorizeArgs(t *testing.T) {
- cgrEv := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: utils.UUIDSha1Prefix(),
- Time: utils.TimePointer(time.Now()),
- Event: map[string]interface{}{
- utils.Account: "1001",
- utils.AnswerTime: "1497106115",
- utils.Category: "call",
- utils.Destination: "1002",
- utils.Direction: utils.META_OUT,
- utils.OriginHost: "127.0.0.1",
- utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
- utils.RequestType: "*prepaid",
- utils.SetupTime: "1497106115",
- utils.Tenant: "cgrates.org",
- utils.ToR: "*voice",
- utils.Usage: "4s",
- },
- }
- expected := &sessions.V1AuthorizeArgs{
- GetMaxUsage: true,
- CGREvent: *cgrEv,
- }
- outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1AuthorizeArgs(cgrEv)
- if !reflect.DeepEqual(expected, outVal) {
- t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
- }
-}
-
-func TestPVAsV1InitSessionArgs(t *testing.T) {
- cgrEv := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: utils.UUIDSha1Prefix(),
- Time: utils.TimePointer(time.Now()),
- Event: map[string]interface{}{
- utils.Account: "1001",
- utils.AnswerTime: "1497106115",
- utils.Category: "call",
- utils.Destination: "1002",
- utils.Direction: utils.META_OUT,
- utils.OriginHost: "127.0.0.1",
- utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
- utils.RequestType: "*prepaid",
- utils.SetupTime: "1497106115",
- utils.Tenant: "cgrates.org",
- utils.ToR: "*voice",
- utils.Usage: "4s",
- },
- }
- expected := &sessions.V1InitSessionArgs{
- InitSession: true,
- CGREvent: *cgrEv,
- }
- outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1InitSessionArgs(cgrEv)
- if !reflect.DeepEqual(expected, outVal) {
- t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
- }
- eInitArgs := &sessions.V1InitSessionArgs{
- InitSession: false,
- AllocateResources: true,
- GetAttributes: true,
- CGREvent: *cgrEv,
- }
- initArgs := processorVars{MetaRadReqType: MetaRadAcctStart, utils.MetaResources: true,
- utils.MetaAttributes: true}.asV1InitSessionArgs(cgrEv)
- if !reflect.DeepEqual(eInitArgs, initArgs) {
- t.Errorf("expecting: %+v, received: %+v", eInitArgs, initArgs)
- }
-}
-
-func TestPVAsV1UpdateSessionArgs(t *testing.T) {
- cgrEv := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: utils.UUIDSha1Prefix(),
- Time: utils.TimePointer(time.Now()),
- Event: map[string]interface{}{
- utils.Account: "1001",
- utils.AnswerTime: "1497106115",
- utils.Category: "call",
- utils.Destination: "1002",
- utils.Direction: utils.META_OUT,
- utils.OriginHost: "127.0.0.1",
- utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
- utils.RequestType: "*prepaid",
- utils.SetupTime: "1497106115",
- utils.Tenant: "cgrates.org",
- utils.ToR: "*voice",
- utils.Usage: "4s",
- },
- }
- expected := &sessions.V1UpdateSessionArgs{
- UpdateSession: true,
- CGREvent: *cgrEv,
- }
- outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1UpdateSessionArgs(cgrEv)
- if !reflect.DeepEqual(expected, outVal) {
- t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
- }
-}
-
-func TestPVAsTerminateSessionArgs(t *testing.T) {
- cgrEv := &utils.CGREvent{
- Tenant: "cgrates.org",
- ID: utils.UUIDSha1Prefix(),
- Time: utils.TimePointer(time.Now()),
- Event: map[string]interface{}{
- utils.Account: "1001",
- utils.AnswerTime: "1497106115",
- utils.Category: "call",
- utils.Destination: "1002",
- utils.Direction: utils.META_OUT,
- utils.OriginHost: "127.0.0.1",
- utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-75c2f57b-51585361",
- utils.RequestType: "*prepaid",
- utils.SetupTime: "1497106115",
- utils.Tenant: "cgrates.org",
- utils.ToR: "*voice",
- utils.Usage: "4s",
- },
- }
- expected := &sessions.V1TerminateSessionArgs{
- TerminateSession: true,
- CGREvent: *cgrEv,
- }
- outVal := processorVars{MetaRadReqType: MetaRadAcctStart}.asV1TerminateSessionArgs(cgrEv)
- if !reflect.DeepEqual(expected, outVal) {
- t.Errorf("Expecting: <%s>, received: <%s>", utils.ToJSON(expected), utils.ToJSON(outVal))
- }
-}
-
func TestRadReplyAppendAttributes(t *testing.T) {
rply := radigo.NewPacket(radigo.AccessRequest, 2, dictRad, coder, "CGRateS.org").Reply()
rplyFlds := []*config.CfgCdrField{
&config.CfgCdrField{Tag: "ReplyCode", FieldId: MetaRadReplyCode, Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("*cgrReply>Attributes>RadReply", utils.INFIELD_SEP)},
+ Value: utils.ParseRSRFieldsMustCompile("*cgrReply.Attributes.RadReply", utils.INFIELD_SEP)},
&config.CfgCdrField{Tag: "Acct-Session-Time", FieldId: "Acct-Session-Time", Type: utils.META_COMPOSED,
- Value: utils.ParseRSRFieldsMustCompile("*cgrReply>MaxUsage{*duration_seconds}", utils.INFIELD_SEP)},
+ Value: utils.ParseRSRFieldsMustCompile("*cgrReply.MaxUsage{*duration_seconds}", utils.INFIELD_SEP)},
}
- procVars := make(processorVars)
- procVars[utils.MetaCGRReply] = map[string]interface{}{
- utils.CapAttributes: map[string]interface{}{
- "RadReply": "AccessAccept",
- utils.Account: "1001",
- },
- utils.CapMaxUsage: time.Duration(time.Hour),
- }
- if err := radReplyAppendAttributes(rply, procVars, rplyFlds); err != nil {
+ agReq := newAgentRequest(nil, nil, "cgrates.org", nil)
+ agReq.CGRReply.Set([]string{utils.CapMaxUsage}, time.Duration(time.Hour), false)
+ agReq.CGRReply.Set([]string{utils.CapAttributes, "RadReply"}, "AccessAccept", false)
+ agReq.CGRReply.Set([]string{utils.CapAttributes, utils.Account}, "1001", false)
+ if err := radReplyAppendAttributes(rply, agReq, rplyFlds); err != nil {
t.Error(err)
}
if rply.Code != radigo.AccessAccept {
diff --git a/agents/radagent.go b/agents/radagent.go
index dd250e4f3..6fb34ee96 100644
--- a/agents/radagent.go
+++ b/agents/radagent.go
@@ -19,8 +19,8 @@ along with this program. If not, see
package agents
import (
+ "errors"
"fmt"
- "strconv"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -88,6 +88,7 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
return
}
agReq := newAgentRequest(dcdr, ra.tenantCfg, ra.cgrCfg.DefaultTenant, ra.filterS)
+ agReq.Vars.Set([]string{MetaRadReqType}, utils.StringToInterface(MetaRadAuth), true)
rpl = req.Reply()
rpl.Code = radigo.AccessAccept
var processed bool
@@ -101,12 +102,12 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
}
}
if err != nil {
- utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, process vars: %+v",
- utils.RadiusAgent, err.Error(), utils.ToJSON(req), procVars))
+ utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, agentRequest: %+v",
+ utils.RadiusAgent, err.Error(), utils.ToJSON(req), utils.ToJSON(agReq)))
return nil, nil
} else if !processed {
- utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, process vars: %+v",
- utils.RadiusAgent, utils.ToJSON(req), procVars))
+ utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, agentRequest: %+v",
+ utils.RadiusAgent, utils.ToJSON(req), utils.ToJSON(agReq)))
return nil, nil
}
return
@@ -115,24 +116,21 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e
// handleAcct handles RADIUS Accounting request
// supports: Acct-Status-Type = Start, Interim-Update, Stop
func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err error) {
- req.SetAVPValues() // populate string values in AVPs
- procVars := make(processorVars)
- if avps := req.AttributesWithName("Acct-Status-Type", ""); len(avps) != 0 { // populate accounting type
- switch avps[0].GetStringValue() { // first AVP found will give out the type of accounting
- case RadAcctStart:
- procVars[MetaRadReqType] = MetaRadAcctStart
- case RadAcctInterimUpdate:
- procVars[MetaRadReqType] = MetaRadAcctUpdate
- case RadAcctStop:
- procVars[MetaRadReqType] = MetaRadAcctStop
- }
+ req.SetAVPValues() // populate string values in AVPs
+ dcdr, err := newRADataProvider(req) // dcdr will provide information from request
+ if err != nil {
+ utils.Logger.Warning(
+ fmt.Sprintf("<%s> error creating decoder: %s",
+ utils.RadiusAgent, err.Error()))
+ return
}
+ agReq := newAgentRequest(dcdr, ra.tenantCfg, ra.cgrCfg.DefaultTenant, ra.filterS)
rpl = req.Reply()
rpl.Code = radigo.AccountingResponse
var processed bool
for _, reqProcessor := range ra.cgrCfg.RadiusAgentCfg().RequestProcessors {
var lclProcessed bool
- if lclProcessed, err = ra.processRequest(reqProcessor, req, procVars, rpl); lclProcessed {
+ if lclProcessed, err = ra.processRequest(reqProcessor, agReq, rpl); lclProcessed {
processed = lclProcessed
}
if err != nil || (lclProcessed && !reqProcessor.ContinueOnSuccess) {
@@ -140,12 +138,12 @@ func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err e
}
}
if err != nil {
- utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, process vars: %+v",
- utils.RadiusAgent, err.Error(), utils.ToJSON(req), procVars))
+ utils.Logger.Err(fmt.Sprintf("<%s> error: <%s> ignoring request: %s, agentRequest: %+v",
+ utils.RadiusAgent, err.Error(), utils.ToJSON(req), utils.ToJSON(agReq)))
return nil, nil
} else if !processed {
- utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, process vars: %+v",
- utils.RadiusAgent, utils.ToJSON(req), procVars))
+ utils.Logger.Err(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, agentRequest: %+v",
+ utils.RadiusAgent, utils.ToJSON(req), utils.ToJSON(agReq)))
return nil, nil
}
return
@@ -178,7 +176,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
case utils.MetaDryRun:
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, CGREvent: %s",
- utils.HTTPAgent, reqProcessor.Id, utils.ToJSON(cgrEv)))
+ utils.RadiusAgent, reqProcessor.Id, utils.ToJSON(cgrEv)))
case utils.MetaAuth:
authArgs := sessions.NewV1AuthorizeArgs(
reqProcessor.Flags.HasKey(utils.MetaAttributes),
@@ -191,7 +189,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
reqProcessor.Flags.HasKey(utils.MetaSuppliersEventCost),
*cgrEv)
var authReply sessions.V1AuthorizeReply
- err = ha.sessionS.Call(utils.SessionSv1AuthorizeEvent,
+ err = ra.sessionS.Call(utils.SessionSv1AuthorizeEvent,
authArgs, &authReply)
if agReq.CGRReply, err = NewCGRReply(&authReply, err); err != nil {
return
@@ -204,7 +202,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
reqProcessor.Flags.HasKey(utils.MetaThresholds),
reqProcessor.Flags.HasKey(utils.MetaStats), *cgrEv)
var initReply sessions.V1InitSessionReply
- err = ha.sessionS.Call(utils.SessionSv1InitiateSession,
+ err = ra.sessionS.Call(utils.SessionSv1InitiateSession,
initArgs, &initReply)
if agReq.CGRReply, err = NewCGRReply(&initReply, err); err != nil {
return
@@ -214,7 +212,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
reqProcessor.Flags.HasKey(utils.MetaAttributes),
reqProcessor.Flags.HasKey(utils.MetaAccounts), *cgrEv)
var updateReply sessions.V1UpdateSessionReply
- err = ha.sessionS.Call(utils.SessionSv1UpdateSession,
+ err = ra.sessionS.Call(utils.SessionSv1UpdateSession,
updateArgs, &updateReply)
if agReq.CGRReply, err = NewCGRReply(&updateReply, err); err != nil {
return
@@ -226,7 +224,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
reqProcessor.Flags.HasKey(utils.MetaThresholds),
reqProcessor.Flags.HasKey(utils.MetaStats), *cgrEv)
var tRply string
- err = ha.sessionS.Call(utils.SessionSv1TerminateSession,
+ err = ra.sessionS.Call(utils.SessionSv1TerminateSession,
terminateArgs, &tRply)
if agReq.CGRReply, err = NewCGRReply(nil, err); err != nil {
return
@@ -237,7 +235,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
reqProcessor.Flags.HasKey(utils.MetaAccounts),
reqProcessor.Flags.HasKey(utils.MetaAttributes), *cgrEv)
var eventRply sessions.V1ProcessEventReply
- err = ha.sessionS.Call(utils.SessionSv1ProcessEvent,
+ err = ra.sessionS.Call(utils.SessionSv1ProcessEvent,
evArgs, &eventRply)
if utils.ErrHasPrefix(err, utils.RalsErrorPrfx) {
cgrEv.Event[utils.Usage] = 0 // avoid further debits
@@ -251,7 +249,7 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
// separate request so we can capture the Terminate/Event also here
if reqProcessor.Flags.HasKey(utils.MetaCDRs) {
var rplyCDRs string
- if err = ha.sessionS.Call(utils.SessionSv1ProcessCDR,
+ if err = ra.sessionS.Call(utils.SessionSv1ProcessCDR,
*cgrEv, &rplyCDRs); err != nil {
agReq.CGRReply.Set([]string{utils.Error}, err.Error(), false)
}
@@ -261,11 +259,13 @@ func (ra *RadiusAgent) processRequest(reqProcessor *config.RARequestProcessor,
} else {
agReq.Reply.Merge(nM)
}
- //update rply *radigo.Packet
+ if err := radReplyAppendAttributes(rply, agReq, reqProcessor.ReplyFields); err != nil {
+ return false, err
+ }
if reqType == utils.MetaDryRun {
utils.Logger.Info(
- fmt.Sprintf("<%s> DRY_RUN, HTTP reply: %s",
- utils.HTTPAgent, utils.ToJSON(rply)))
+ fmt.Sprintf("<%s> DRY_RUN, Radius reply: %s",
+ utils.RadiusAgent, utils.ToJSON(rply)))
}
return true, nil
}
diff --git a/agents/radagent_it_test.go b/agents/radagent_it_test.go
index a7d3c9eaf..bb5be8d99 100644
--- a/agents/radagent_it_test.go
+++ b/agents/radagent_it_test.go
@@ -191,7 +191,7 @@ func TestRAitAcctStart(t *testing.T) {
}
// Make sure the sessin is managed by SMG
var aSessions []*sessions.ActiveSession
- if err := raRPC.Call("SMGenericV1.GetActiveSessions",
+ if err := raRPC.Call(utils.SessionSv1GetActiveSessions,
map[string]string{utils.RunID: utils.META_DEFAULT,
utils.OriginID: "e4921177ab0e3586c37f6a185864b71a@0:0:0:0:0:0:0:0-51585361-75c2f57b"},
&aSessions); err != nil {
@@ -279,7 +279,7 @@ func TestRAitAcctStop(t *testing.T) {
t.Errorf("Unexpected CDR CostSource received for CDR: %v", cdrs[0])
}
if cdrs[0].Cost != 0.01 {
- t.Errorf("Unexpected CDR Cost received for CDR: %v", cdrs[0])
+ t.Errorf("Unexpected CDR Cost received for CDR: %v", cdrs[0].Cost)
}
}
}
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index 2e3171d8b..022e6d780 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -324,7 +324,7 @@ func startRadiusAgent(internalSMGChan chan rpcclient.RpcClientConnection, exitCh
return
}
}
- ra, err := agents.NewRadiusAgent(cfg, smgConn)
+ ra, err := agents.NewRadiusAgent(cfg, filterS, smgConn)
if err != nil {
utils.Logger.Err(fmt.Sprintf(" error: <%s>", err.Error()))
exitChan <- true
diff --git a/data/conf/samples/radagent/cgrates.json b/data/conf/samples/radagent/cgrates.json
index 930b4d721..f255714f2 100644
--- a/data/conf/samples/radagent/cgrates.json
+++ b/data/conf/samples/radagent/cgrates.json
@@ -29,18 +29,6 @@
"rals": {
"enabled": true,
- "cdrstats_conns": [
- {"address": "*internal"}
- ],
- "pubsubs_conns": [
- {"address": "*internal"}
- ],
- "users_conns": [
- {"address": "*internal"}
- ],
- "aliases_conns": [
- {"address": "*internal"}
- ],
},
"scheduler": {
@@ -52,26 +40,6 @@
"rals_conns": [
{"address": "*internal"}
],
- "cdrstats_conns": [
- {"address": "*internal"}
- ],
-},
-
-"cdrstats": {
- "enabled": true,
-},
-
-"pubsubs": {
- "enabled": true, // starts PubSub service: .
-},
-
-"aliases": {
- "enabled": true, // starts Aliases service: .
-},
-
-"users": {
- "enabled": true,
- "indexes": ["SubscriberId"],
},
"resources": {
@@ -88,6 +56,18 @@
"sessions": {
"enabled": true,
+ "attributes_conns": [
+ {"address": "127.0.0.1:2012", "transport": "*json"}
+ ],
+ "cdrs_conns": [
+ {"address": "127.0.0.1:2012", "transport": "*json"}
+ ],
+ "rals_conns": [
+ {"address": "127.0.0.1:2012", "transport": "*json"}
+ ],
+ "resources_conns": [
+ {"address": "127.0.0.1:2012", "transport": "*json"}
+ ],
"debit_interval": "10s",
},
@@ -99,70 +79,73 @@
"request_processors": [
{
"id": "KamailioAuth",
- "filters": ["*string:*request.request_type:*radAuth"],
- "flags": ["*dryrun"],
+ "filters": ["*string:*vars.*radReqType:*radAuth"],
+ "flags": ["*auth", "*accounts",],
+ "continue_on_success": false,
"request_fields":[
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant",
"value": "*prepaid", "mandatory": true},
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
- "value": "Acct-Session-Id;^-;Sip-From-Tag", "mandatory": true},
+ "value": "*request.Acct-Session-Id;^-;*request.Sip-From-Tag", "mandatory": true},
{"tag": "Account", "field_id": "Account", "type": "*composed",
- "value": "User-Name", "mandatory": true},
+ "value": "*request.User-Name", "mandatory": true},
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
- "value": "Called-Station-Id", "mandatory": true},
+ "value": "*request.Called-Station-Id", "mandatory": true},
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed",
- "value": "Event-Timestamp", "mandatory": true},
+ "value": "*request.Event-Timestamp", "mandatory": true},
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
- "value": "Event-Timestamp", "mandatory": true},
+ "value": "*request.Event-Timestamp", "mandatory": true},
],
"reply_fields":[
{"tag": "MaxUsage", "field_id": "SIP-AVP", "type": "*composed",
- "value": "^session_max_time#;*cgrReply>MaxUsage{*duration_seconds}", "mandatory": true},
+ "value": "^session_max_time#;*cgrReply.MaxUsage{*duration_seconds}", "mandatory": true},
],
},
{
"id": "KamailioAccountingStart",
- "filters": ["*string:*request.request_type:*radAcctStart"],
- "flags": ["*dryrun"],
+ "filters": ["*string:*request.Acct-Status-Type:Start"],
+ "flags": ["*initiate","*attributes","*resources","*accounts"],
+ "continue_on_success": false,
"request_fields":[
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant",
"value": "*prepaid", "mandatory": true},
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
- "value": "Acct-Session-Id;^-;Sip-From-Tag;^-;Sip-To-Tag", "mandatory": true},
+ "value": "*request.Acct-Session-Id;^-;*request.Sip-From-Tag;^-;*request.Sip-To-Tag", "mandatory": true},
{"tag": "OriginHost", "field_id": "OriginHost", "type": "*composed",
- "value": "NAS-IP-Address", "mandatory": true},
+ "value": "*request.NAS-IP-Address", "mandatory": true},
{"tag": "Account", "field_id": "Account", "type": "*composed",
- "value": "User-Name", "mandatory": true},
+ "value": "*request.User-Name", "mandatory": true},
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
- "value": "Called-Station-Id", "mandatory": true},
+ "value": "*request.Called-Station-Id", "mandatory": true},
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed",
- "value": "Ascend-User-Acct-Time", "mandatory": true},
+ "value": "*request.Ascend-User-Acct-Time", "mandatory": true},
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
- "value": "Ascend-User-Acct-Time", "mandatory": true},
+ "value": "*request.Ascend-User-Acct-Time", "mandatory": true},
],
"reply_fields":[],
},
{
"id": "KamailioAccountingStop",
- "filters": ["*string:*request.request_type:*radAcctStop"],
- "flags": ["*dryrun"],
+ "filters": ["*string:*request.Acct-Status-Type:Stop"],
+ "flags": ["*terminate","*resources","*accounts","*cdrs"],
+ "continue_on_success": false,
"request_fields":[
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant",
"value": "*prepaid", "mandatory": true},
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
- "value": "Acct-Session-Id;^-;Sip-From-Tag;^-;Sip-To-Tag", "mandatory": true},
+ "value": "*request.Acct-Session-Id;^-;*request.Sip-From-Tag;^-;*request.Sip-To-Tag", "mandatory": true},
{"tag": "OriginHost", "field_id": "OriginHost", "type": "*composed",
- "value": "NAS-IP-Address", "mandatory": true},
+ "value": "*request.NAS-IP-Address", "mandatory": true},
{"tag": "Account", "field_id": "Account", "type": "*composed",
- "value": "User-Name", "mandatory": true},
+ "value": "*request.User-Name", "mandatory": true},
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
- "value": "Called-Station-Id", "mandatory": true},
+ "value": "*request.Called-Station-Id", "mandatory": true},
{"tag": "SetupTime", "field_id": "SetupTime", "type": "*composed",
- "value": "Ascend-User-Acct-Time", "mandatory": true},
+ "value": "*request.Ascend-User-Acct-Time", "mandatory": true},
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
- "value": "Ascend-User-Acct-Time", "mandatory": true},
- {"tag": "Usage", "field_id": "Usage", "type": "*handler", "handler_id": "*usage_difference",
- "value": "Event-Timestamp;^|;Ascend-User-Acct-Time", "mandatory": true},
+ "value": "*request.Ascend-User-Acct-Time", "mandatory": true},
+ {"tag": "Usage", "field_id": "Usage", "type": "*usage_difference",
+ "value": "*request.Event-Timestamp;*request.Ascend-User-Acct-Time", "mandatory": true},
],
"reply_fields":[],
},
diff --git a/sessions/sessions.go b/sessions/sessions.go
index 3da5feae9..783093867 100644
--- a/sessions/sessions.go
+++ b/sessions/sessions.go
@@ -1902,6 +1902,7 @@ func (smg *SMGeneric) BiRPCv1TerminateSession(clnt rpcclient.RpcClientConnection
if !args.TerminateSession && !args.ReleaseResources {
return utils.NewErrMandatoryIeMissing("subsystems")
}
+ //
if args.CGREvent.Tenant == "" {
args.CGREvent.Tenant = smg.cgrCfg.DefaultTenant
}
diff --git a/utils/consts.go b/utils/consts.go
index 53e4106c5..802749ae9 100755
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -323,6 +323,7 @@ const (
TRIGGER_BALANCE_EXPIRED = "*balance_expired"
HIERARCHY_SEP = ">"
META_COMPOSED = "*composed"
+ META_USAGE_DIFFERENCE = "*usage_difference"
MetaString = "*string"
NegativePrefix = "!"
MatchStartPrefix = "^"
@@ -523,6 +524,7 @@ const (
MetaDryRun = "*dryrun"
Event = "Event"
EmptyString = ""
+ AgentRequest = "AgentRequest"
)
// Migrator Action