radius_agent configuration options in cgrates.json

This commit is contained in:
DanB
2017-04-21 20:33:47 +02:00
parent 15f7840fdc
commit 10f884835d
6 changed files with 263 additions and 2 deletions

View File

@@ -69,6 +69,7 @@ func NewDefaultCGRConfig() (*CGRConfig, error) {
cfg.SmOsipsConfig = new(SmOsipsConfig)
cfg.smAsteriskCfg = new(SMAsteriskCfg)
cfg.diameterAgentCfg = new(DiameterAgentCfg)
cfg.radiusAgentCfg = new(RadiusAgentCfg)
cfg.ConfigReloads = make(map[string]chan struct{})
cfg.ConfigReloads[utils.CDRC] = make(chan struct{}, 1)
cfg.ConfigReloads[utils.CDRC] <- struct{}{} // Unlock the channel
@@ -249,6 +250,7 @@ type CGRConfig struct {
SmOsipsConfig *SmOsipsConfig // SMOpenSIPS Configuration
smAsteriskCfg *SMAsteriskCfg // SMAsterisk Configuration
diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration
radiusAgentCfg *RadiusAgentCfg // RadiusAgent configuration
HistoryServerEnabled bool // Starts History as server: <true|false>.
HistoryDir string // Location on disk where to store history files.
HistorySaveInterval time.Duration // The timout duration between pubsub writes
@@ -469,6 +471,13 @@ func (self *CGRConfig) checkConfigSanity() error {
}
}
}
if self.radiusAgentCfg.Enabled {
for _, raSMGConn := range self.radiusAgentCfg.SMGenericConns {
if raSMGConn.Address == utils.MetaInternal && !self.SmGenericConfig.Enabled {
return errors.New("SMGeneric not enabled but referenced by RadiusAgent component")
}
}
}
// ResourceLimiter checks
if self.resourceLimiterCfg != nil && self.resourceLimiterCfg.Enabled {
for _, connCfg := range self.resourceLimiterCfg.CDRStatConns {
@@ -575,6 +584,11 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
return err
}
jsnRACfg, err := jsnCfg.RadiusAgentJsonCfg()
if err != nil {
return err
}
jsnHistServCfg, err := jsnCfg.HistServJsonCfg()
if err != nil {
return err
@@ -983,6 +997,12 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) error {
}
}
if jsnRACfg != nil {
if err := self.radiusAgentCfg.loadFromJsonCfg(jsnRACfg); err != nil {
return err
}
}
if jsnHistServCfg != nil {
if jsnHistServCfg.Enabled != nil {
self.HistoryServerEnabled = *jsnHistServCfg.Enabled
@@ -1067,6 +1087,10 @@ func (self *CGRConfig) DiameterAgentCfg() *DiameterAgentCfg {
return self.diameterAgentCfg
}
func (self *CGRConfig) RadiusAgentCfg() *RadiusAgentCfg {
return self.radiusAgentCfg
}
// ToDo: fix locking here
func (self *CGRConfig) ResourceLimiterCfg() *ResourceLimiterConfig {
return self.resourceLimiterCfg

View File

@@ -358,8 +358,8 @@ const CGRATES_CFG_JSON = `
"request_filter": "Subscription-Id>Subscription-Id-Type(0)", // filter requests processed by this processor
"flags": [], // flags to influence processing behavior
"continue_on_success": false, // continue to the next template if executed
"append_cca": true, // when continuing will append cca fields to the previous ones
"ccr_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
"append_cca": true, // when continuing will append cca fields of the the previous one
"ccr_fields":[ // import content_fields template, tag will match internally CDR field
{"tag": "TOR", "field_id": "ToR", "type": "*composed", "value": "^*voice", "mandatory": true},
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed", "value": "Session-Id", "mandatory": true},
{"tag": "RequestType", "field_id": "RequestType", "type": "*composed", "value": "^*users", "mandatory": true},
@@ -382,6 +382,34 @@ const CGRATES_CFG_JSON = `
},
"radius_agent": {
"enabled": false, // enables the radius agent: <true|false>
"listen_auth": "127.0.0.1:1812", // address where to listen for radius authentication requests <x.y.z.y:1234>
"listen_acct": "127.0.0.1:1813", // address where to listen for radius accounting requests <x.y.z.y:1234>
"dictionaries_dir": "/usr/share/cgrates/radius/dict/", // path towards directory holding additional dictionaries to load (extra to RFC)
"sm_generic_conns": [
{"address": "*internal"} // connection towards SMG component for session management
],
"create_cdr": true, // create CDR out of Accounting-Stop and send it to SMG component
"cdr_requires_session": false, // only create CDR if there is an active session at terminate
"timezone": "", // timezone for timestamps where not specified, empty for general defaults <""|UTC|Local|$IANA_TZ_DB>
"request_processors": [
{
"id": "*default", // formal identifier of this processor
"dry_run": false, // do not send the events to SMG, just log them
"request_filter": "", // filter requests processed by this processor
"flags": [], // flags to influence processing behavior
"continue_on_success": false, // continue to the next template if executed
"append_reply": true, // when continuing will append reply fields to the next template
"request_fields":[ // import content_fields template, tag will match internally CDR field
],
"reply_fields":[ // fields returned in radius reply
],
},
],
},
"historys": {
"enabled": false, // starts History service: <true|false>.
"history_dir": "/var/lib/cgrates/history", // location on disk where to store history files.

View File

@@ -49,6 +49,7 @@ const (
KAMAILIO_JSN = "kamailio"
OSIPS_JSN = "opensips"
DA_JSN = "diameter_agent"
RA_JSN = "radius_agent"
HISTSERV_JSN = "historys"
PUBSUBSERV_JSN = "pubsubs"
ALIASESSERV_JSN = "aliases"
@@ -285,6 +286,18 @@ func (self CgrJsonCfg) DiameterAgentJsonCfg() (*DiameterAgentJsonCfg, error) {
return cfg, nil
}
func (self CgrJsonCfg) RadiusAgentJsonCfg() (*RadiusAgentJsonCfg, error) {
rawCfg, hasKey := self[RA_JSN]
if !hasKey {
return nil, nil
}
cfg := new(RadiusAgentJsonCfg)
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

@@ -605,6 +605,40 @@ func TestDiameterAgentJsonCfg(t *testing.T) {
}
}
func TestRadiusAgentJsonCfg(t *testing.T) {
eCfg := &RadiusAgentJsonCfg{
Enabled: utils.BoolPointer(false),
Listen_auth: utils.StringPointer("127.0.0.1:1812"),
Listen_acct: utils.StringPointer("127.0.0.1:1813"),
Dictionaries_dir: utils.StringPointer("/usr/share/cgrates/radius/dict/"),
Sm_generic_conns: &[]*HaPoolJsonCfg{
&HaPoolJsonCfg{
Address: utils.StringPointer(utils.MetaInternal),
}},
Create_cdr: utils.BoolPointer(true),
Cdr_requires_session: utils.BoolPointer(false),
Timezone: utils.StringPointer(""),
Request_processors: &[]*RAReqProcessorJsnCfg{
&RAReqProcessorJsnCfg{
Id: utils.StringPointer("*default"),
Dry_run: utils.BoolPointer(false),
Request_filter: utils.StringPointer(""),
Flags: utils.StringSlicePointer([]string{}),
Continue_on_success: utils.BoolPointer(false),
Append_reply: utils.BoolPointer(true),
Request_fields: &[]*CdrFieldJsonCfg{},
Reply_fields: &[]*CdrFieldJsonCfg{},
},
},
}
if cfg, err := dfCgrJsonCfg.RadiusAgentJsonCfg(); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
rcv := *cfg.Request_processors
t.Errorf("Received: %+v", rcv[0].Reply_fields)
}
}
func TestDfHistServJsonCfg(t *testing.T) {
eCfg := &HistServJsonCfg{
Enabled: utils.BoolPointer(false),

View File

@@ -339,6 +339,30 @@ type DARequestProcessorJsnCfg struct {
CCA_fields *[]*CdrFieldJsonCfg
}
// Radius Agent configuration section
type RadiusAgentJsonCfg struct {
Enabled *bool
Listen_auth *string
Listen_acct *string
Dictionaries_dir *string
Sm_generic_conns *[]*HaPoolJsonCfg
Create_cdr *bool
Cdr_requires_session *bool
Timezone *string
Request_processors *[]*RAReqProcessorJsnCfg
}
type RAReqProcessorJsnCfg struct {
Id *string
Dry_run *bool
Request_filter *string
Flags *[]string
Continue_on_success *bool
Append_reply *bool
Request_fields *[]*CdrFieldJsonCfg
Reply_fields *[]*CdrFieldJsonCfg
}
// History server config section
type HistServJsonCfg struct {
Enabled *bool

138
config/raconfig.go Normal file
View File

@@ -0,0 +1,138 @@
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) 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 (
"github.com/cgrates/cgrates/utils"
)
type RadiusAgentCfg struct {
Enabled bool
ListenAuth string
ListenAcct string
DictionariesDir string
SMGenericConns []*HaPoolConfig
CreateCDR bool
CDRRequiresSession bool
Timezone string
RequestProcessors []*RARequestProcessor
}
func (self *RadiusAgentCfg) loadFromJsonCfg(jsnCfg *RadiusAgentJsonCfg) error {
if jsnCfg == nil {
return nil
}
if jsnCfg.Enabled != nil {
self.Enabled = *jsnCfg.Enabled
}
if jsnCfg.Listen_auth != nil {
self.ListenAuth = *jsnCfg.Listen_auth
}
if jsnCfg.Listen_acct != nil {
self.ListenAcct = *jsnCfg.Listen_acct
}
if jsnCfg.Dictionaries_dir != nil {
self.DictionariesDir = *jsnCfg.Dictionaries_dir
}
if jsnCfg.Sm_generic_conns != nil {
self.SMGenericConns = make([]*HaPoolConfig, len(*jsnCfg.Sm_generic_conns))
for idx, jsnHaCfg := range *jsnCfg.Sm_generic_conns {
self.SMGenericConns[idx] = NewDfltHaPoolConfig()
self.SMGenericConns[idx].loadFromJsonCfg(jsnHaCfg)
}
}
if jsnCfg.Create_cdr != nil {
self.CreateCDR = *jsnCfg.Create_cdr
}
if jsnCfg.Cdr_requires_session != nil {
self.CDRRequiresSession = *jsnCfg.Cdr_requires_session
}
if jsnCfg.Timezone != nil {
self.Timezone = *jsnCfg.Timezone
}
if jsnCfg.Request_processors != nil {
for _, reqProcJsn := range *jsnCfg.Request_processors {
rp := new(RARequestProcessor)
var haveID bool
for _, rpSet := range self.RequestProcessors {
if reqProcJsn.Id != nil && rpSet.Id == *reqProcJsn.Id {
rp = rpSet // Will load data into the one set
haveID = true
break
}
}
if err := rp.loadFromJsonCfg(reqProcJsn); err != nil {
return nil
}
if !haveID {
self.RequestProcessors = append(self.RequestProcessors, rp)
}
}
}
return nil
}
// One Diameter request processor configuration
type RARequestProcessor struct {
Id string
DryRun bool
RequestFilter utils.RSRFields
Flags utils.StringMap // Various flags to influence behavior
ContinueOnSuccess bool
AppendReply bool
RequestFields []*CfgCdrField
ReplyFields []*CfgCdrField
}
func (self *RARequestProcessor) loadFromJsonCfg(jsnCfg *RAReqProcessorJsnCfg) 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.Flags != nil {
self.Flags = utils.StringMapFromSlice(*jsnCfg.Flags)
}
if jsnCfg.Continue_on_success != nil {
self.ContinueOnSuccess = *jsnCfg.Continue_on_success
}
if jsnCfg.Append_reply != nil {
self.AppendReply = *jsnCfg.Append_reply
}
if jsnCfg.Request_fields != nil {
if self.RequestFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Request_fields); err != nil {
return err
}
}
if jsnCfg.Reply_fields != nil {
if self.ReplyFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Reply_fields); err != nil {
return err
}
}
return nil
}