DiameterAgent config skel

This commit is contained in:
DanB
2015-11-13 19:11:38 +01:00
parent cc6f614aee
commit 04c8c10877
8 changed files with 236 additions and 1 deletions

View File

@@ -65,6 +65,7 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
cfg.SmFsConfig = new(SmFsConfig)
cfg.SmKamConfig = new(SmKamConfig)
cfg.SmOsipsConfig = new(SmOsipsConfig)
cfg.DiameterAgentCfg = new(DiameterAgentCfg)
cfg.ConfigReloads = make(map[string]chan struct{})
cfg.ConfigReloads[utils.CDRC] = make(chan struct{}, 1)
cfg.ConfigReloads[utils.CDRC] <- struct{}{} // Unlock the channel
@@ -72,6 +73,8 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
cfg.ConfigReloads[utils.CDRE] <- struct{}{} // Unlock the channel
cfg.ConfigReloads[utils.SURETAX] = make(chan struct{}, 1)
cfg.ConfigReloads[utils.SURETAX] <- struct{}{} // Unlock the channel
cfg.ConfigReloads[utils.DIAMETER_AGENT] = make(chan struct{}, 1)
cfg.ConfigReloads[utils.DIAMETER_AGENT] <- struct{}{} // Unlock the channel
cgrJsonCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON))
if err != nil {
return nil, err
@@ -229,6 +232,7 @@ type CGRConfig struct {
SmFsConfig *SmFsConfig // SM-FreeSWITCH configuration
SmKamConfig *SmKamConfig // SM-Kamailio Configuration
SmOsipsConfig *SmOsipsConfig // SM-OpenSIPS Configuration
DiameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration
HistoryServer string // Address where to reach the master history server: <internal|x.y.z.y:1234>
HistoryServerEnabled bool // Starts History as server: <true|false>.
HistoryDir string // Location on disk where to store history files.
@@ -461,6 +465,11 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
return err
}
jsnDACfg, err := jsnCfg.DiameterAgentJsonCfg()
if err != nil {
return err
}
jsnHistServCfg, err := jsnCfg.HistServJsonCfg()
if err != nil {
return err
@@ -782,6 +791,12 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
}
}
if jsnDACfg != nil {
if err := self.DiameterAgentCfg.loadFromJsonCfg(jsnDACfg); err != nil {
return err
}
}
if jsnHistServCfg != nil {
if jsnHistServCfg.Enabled != nil {
self.HistoryServerEnabled = *jsnHistServCfg.Enabled

View File

@@ -259,6 +259,36 @@ const CGRATES_CFG_JSON = `
},
"diameter_agent": {
"enabled": false, // enables the diameter agent: <true|false>
"listen": "127.0.0.1:3868", // address where to listen for diameter requests <x.y.z.y:1234>
"timezone": "", // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
"request_processors": [
{
"id": "*default", // Identifier of this processor
"dry_run": false, // do not send the CDRs to CDRS, just parse them
"request_filter": "Subscription-Id>Subscription-Type(0)", // filter requests processed by this processor
"continue_on_success": false, // continue to the next template if executed
"content_fields":[ // import content_fields template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
{"tag": "tor", "cdr_field_id": "TOR", "type": "cdrfield", "value": "^*voice", "mandatory": true},
{"tag": "accid", "cdr_field_id": "AccId", "type": "cdrfield", "value": "Session-Id", "mandatory": true},
{"tag": "reqtype", "cdr_field_id": "ReqType", "type": "cdrfield", "value": "^*users", "mandatory": true},
{"tag": "direction", "cdr_field_id": "Direction", "type": "cdrfield", "value": "^*out", "mandatory": true},
{"tag": "tenant", "cdr_field_id": "Tenant", "type": "cdrfield", "value": "^*users", "mandatory": true},
{"tag": "category", "cdr_field_id": "Category", "type": "cdrfield", "value": "^call_;~Calling-Vlr-Number:s/^$/33000/;~Calling-Vlr-Number:s/^(\\d{5})/${1}/", "mandatory": true},
{"tag": "account", "cdr_field_id": "Account", "type": "cdrfield", "value": "^*users", "mandatory": true},
{"tag": "subject", "cdr_field_id": "Subject", "type": "cdrfield", "value": "^*users", "mandatory": true},
{"tag": "destination", "cdr_field_id": "Destination", "type": "cdrfield", "value": "Real-Called-Number", "mandatory": true},
{"tag": "setup_time", "cdr_field_id": "SetupTime", "type": "cdrfield", "value": "Event-Time", "mandatory": true},
{"tag": "answer_time", "cdr_field_id": "AnswerTime", "type": "cdrfield", "value": "Event-Time", "mandatory": true},
{"tag": "usage", "cdr_field_id": "Usage", "type": "cdrfield", "value": "CC-Time", "mandatory": true},
{"tag": "subscriber_id", "cdr_field_id": "SubscriberId", "type": "cdrfield", "value": "Subscription-Id>Subscription-Id-Data", "mandatory": true},
],
},
],
},
"historys": {
"enabled": false, // starts History service: <true|false>.
"history_dir": "/var/log/cgrates/history", // location on disk where to store history files.

View File

@@ -48,6 +48,7 @@ const (
FS_JSN = "freeswitch"
KAMAILIO_JSN = "kamailio"
OSIPS_JSN = "opensips"
DA_JSN = "diameter_agent"
HISTSERV_JSN = "historys"
PUBSUBSERV_JSN = "pubsubs"
ALIASESSERV_JSN = "aliases"
@@ -247,6 +248,18 @@ func (self CgrJsonCfg) SmOsipsJsonCfg() (*SmOsipsJsonCfg, error) {
return cfg, nil
}
func (self CgrJsonCfg) DiameterAgentJsonCfg() (*DiameterAgentJsonCfg, error) {
rawCfg, hasKey := self[DA_JSN]
if !hasKey {
return nil, nil
}
cfg := new(DiameterAgentJsonCfg)
if err := json.Unmarshal(*rawCfg, cfg); err != nil {
return nil, err
}
return cfg, nil
}
func (self CgrJsonCfg) HistServJsonCfg() (*HistServJsonCfg, error) {
rawCfg, hasKey := self[HISTSERV_JSN]
if !hasKey {

View File

@@ -414,6 +414,55 @@ func TestSmOsipsJsonCfg(t *testing.T) {
}
}
func TestDiameterAgentJsonCfg(t *testing.T) {
eCfg := &DiameterAgentJsonCfg{
Enabled: utils.BoolPointer(false),
Listen: utils.StringPointer("127.0.0.1:3868"),
Timezone: utils.StringPointer(""),
Request_processors: &[]*DARequestProcessorJsnCfg{
&DARequestProcessorJsnCfg{
Id: utils.StringPointer("*default"),
Dry_run: utils.BoolPointer(false),
Request_filter: utils.StringPointer("Subscription-Id>Subscription-Type(0)"),
Continue_on_success: utils.BoolPointer(false),
Content_fields: &[]*CdrFieldJsonCfg{
&CdrFieldJsonCfg{Tag: utils.StringPointer("tor"), Cdr_field_id: utils.StringPointer(utils.TOR), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^*voice"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("accid"), Cdr_field_id: utils.StringPointer(utils.ACCID), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("Session-Id"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("reqtype"), Cdr_field_id: utils.StringPointer(utils.REQTYPE), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^*users"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("direction"), Cdr_field_id: utils.StringPointer(utils.DIRECTION), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^*out"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("tenant"), Cdr_field_id: utils.StringPointer(utils.TENANT), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^*users"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("category"), Cdr_field_id: utils.StringPointer(utils.CATEGORY), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^call_;~Calling-Vlr-Number:s/^$/33000/;~Calling-Vlr-Number:s/^(\\d{5})/${1}/"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("account"), Cdr_field_id: utils.StringPointer(utils.ACCOUNT), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^*users"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("subject"), Cdr_field_id: utils.StringPointer(utils.SUBJECT), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("^*users"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("destination"), Cdr_field_id: utils.StringPointer(utils.DESTINATION), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("Real-Called-Number"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("setup_time"), Cdr_field_id: utils.StringPointer(utils.SETUP_TIME), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("Event-Time"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("answer_time"), Cdr_field_id: utils.StringPointer(utils.ANSWER_TIME), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("Event-Time"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("usage"), Cdr_field_id: utils.StringPointer(utils.USAGE), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("CC-Time"), Mandatory: utils.BoolPointer(true)},
&CdrFieldJsonCfg{Tag: utils.StringPointer("subscriber_id"), Cdr_field_id: utils.StringPointer("SubscriberId"), Type: utils.StringPointer(utils.CDRFIELD),
Value: utils.StringPointer("Subscription-Id>Subscription-Id-Data"), Mandatory: utils.BoolPointer(true)},
},
},
},
}
if cfg, err := dfCgrJsonCfg.DiameterAgentJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
t.Error("Received: ", cfg)
}
}
func TestDfHistServJsonCfg(t *testing.T) {
eCfg := &HistServJsonCfg{
Enabled: utils.BoolPointer(false),

95
config/daconfig.go Normal file
View File

@@ -0,0 +1,95 @@
/*
Real-time Charging System for Telecom & ISP environments
Copyright (C) 2012-2015 ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package config
import (
//"time"
"github.com/cgrates/cgrates/utils"
)
type DiameterAgentCfg struct {
Enabled bool // enables the diameter agent: <true|false>
Listen string // address where to listen for diameter requests <x.y.z.y:1234>
Timezone string // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
RequestProcessors []*DARequestProcessor
}
func (self *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg) error {
if jsnCfg == nil {
return nil
}
if jsnCfg.Enabled != nil {
self.Enabled = *jsnCfg.Enabled
}
if jsnCfg.Listen != nil {
self.Listen = *jsnCfg.Listen
}
if jsnCfg.Timezone != nil {
self.Timezone = *jsnCfg.Timezone
}
if jsnCfg.Request_processors != nil {
for _, reqProcJsn := range *jsnCfg.Request_processors {
rp := new(DARequestProcessor)
for _, rpSet := range self.RequestProcessors {
if reqProcJsn.Id != nil && rpSet.Id == *reqProcJsn.Id {
rp = rpSet // Will load data into the one set
break
}
}
if err := rp.loadFromJsonCfg(reqProcJsn); err != nil {
return nil
}
}
}
return nil
}
// One Diameter request processor configuration
type DARequestProcessor struct {
Id string
DryRun bool
RequestFilter utils.RSRFields
ContinueOnSuccess bool
ContentFields []*CfgCdrField
}
func (self *DARequestProcessor) loadFromJsonCfg(jsnCfg *DARequestProcessorJsnCfg) error {
if jsnCfg == nil {
return nil
}
if jsnCfg.Id != nil {
self.Id = *jsnCfg.Id
}
if jsnCfg.Dry_run != nil {
self.DryRun = *jsnCfg.Dry_run
}
var err error
if jsnCfg.Request_filter != nil {
if self.RequestFilter, err = utils.ParseRSRFields(*jsnCfg.Request_filter, utils.INFIELD_SEP); err != nil {
return err
}
}
if jsnCfg.Content_fields != nil {
if self.ContentFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Content_fields); err != nil {
return err
}
}
return nil
}

View File

@@ -235,6 +235,23 @@ type OsipsConnJsonCfg struct {
Reconnects *int
}
// DiameterAgent configuration
type DiameterAgentJsonCfg struct {
Enabled *bool // enables the diameter agent: <true|false>
Listen *string // address where to listen for diameter requests <x.y.z.y:1234>
Timezone *string // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
Request_processors *[]*DARequestProcessorJsnCfg
}
// One Diameter request processor configuration
type DARequestProcessorJsnCfg struct {
Id *string
Dry_run *bool
Request_filter *string
Continue_on_success *bool
Content_fields *[]*CdrFieldJsonCfg
}
// History server config section
type HistServJsonCfg struct {
Enabled *bool

View File

@@ -239,6 +239,7 @@ const (
EXTRA_FIELDS = "ExtraFields"
META_SURETAX = "*sure_tax"
SURETAX = "suretax"
DIAMETER_AGENT = "diameter_agent"
COUNTER_EVENT = "*event"
COUNTER_BALANCE = "*balance"
EVENT_NAME = "EventName"

View File

@@ -20,9 +20,10 @@ package utils
import (
"archive/zip"
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
@@ -406,3 +407,17 @@ func ConvertIfaceToString(fld interface{}) (string, bool) {
}
return strVal, converted
}
// Simple object cloner, b should be a pointer towards a value into which we want to decode
func Clone(a, b interface{}) error {
buff := new(bytes.Buffer)
enc := gob.NewEncoder(buff)
dec := gob.NewDecoder(buff)
if err := enc.Encode(a); err != nil {
return err
}
if err := dec.Decode(b); err != nil {
return err
}
return nil
}