cfg: add stats/thresholds_conns to radius_agent

This commit is contained in:
ionutboangiu
2025-06-17 17:01:16 +03:00
committed by Dan Christian Bogos
parent d71327a00e
commit f95273db30
7 changed files with 284 additions and 241 deletions

View File

@@ -1048,6 +1048,8 @@ const CGRATES_CFG_JSON = `
"*default": "/usr/share/cgrates/radius/dict/", // key represents the client IP or catch-all <*default|$client_ip>
},
"sessions_conns": ["*internal"],
"stats_conns": [], // connections to StatS, empty to disable: <""|*internal|$rpc_conns_id>
"thresholds_conns": [], // connections to ThresholdS, empty to disable: <""|*internal|$rpc_conns_id>
"request_processors": [] // request processors to be applied to Radius messages
},

View File

@@ -761,18 +761,20 @@ func TestDiameterAgentJsonCfg(t *testing.T) {
func TestRadiusAgentJsonCfg(t *testing.T) {
eCfg := &RadiusAgentJsonCfg{
Enabled: utils.BoolPointer(false),
Listen_net: utils.StringPointer("udp"),
Listen_auth: utils.StringPointer("127.0.0.1:1812"),
Listen_acct: utils.StringPointer("127.0.0.1:1813"),
Client_secrets: map[string]string{
Enabled: utils.BoolPointer(false),
ListenNet: utils.StringPointer("udp"),
ListenAuth: utils.StringPointer("127.0.0.1:1812"),
ListenAcct: utils.StringPointer("127.0.0.1:1813"),
ClientSecrets: map[string]string{
utils.MetaDefault: "CGRateS.org",
},
Client_dictionaries: map[string]string{
ClientDictionaries: map[string]string{
utils.MetaDefault: "/usr/share/cgrates/radius/dict/",
},
Sessions_conns: &[]string{utils.MetaInternal},
Request_processors: &[]*ReqProcessorJsnCfg{},
SessionSConns: &[]string{utils.MetaInternal},
StatSConns: &[]string{},
ThresholdSConns: &[]string{},
RequestProcessors: &[]*ReqProcessorJsnCfg{},
}
dfCgrJSONCfg, err := NewCgrJsonCfgFromBytes([]byte(CGRATES_CFG_JSON))
if err != nil {
@@ -782,8 +784,8 @@ func TestRadiusAgentJsonCfg(t *testing.T) {
if err := dfCgrJSONCfg.GetSection(context.Background(), RadiusAgentJSON, cfg); err != nil {
t.Error(err)
} else if !reflect.DeepEqual(eCfg, cfg) {
rcv := *cfg.Request_processors
t.Errorf("Received: %+v", rcv)
rcv := *cfg.RequestProcessors
t.Errorf("Received: %+v", utils.ToJSON(rcv))
}
}

File diff suppressed because one or more lines are too long

View File

@@ -375,6 +375,22 @@ func (cfg *CGRConfig) checkConfigSanity() error {
return fmt.Errorf("<%s> connection with id: <%s> not defined", utils.RadiusAgent, connID)
}
}
for _, connID := range cfg.radiusAgentCfg.StatSConns {
if strings.HasPrefix(connID, utils.MetaInternal) && !cfg.statsCfg.Enabled {
return fmt.Errorf("<%s> not enabled but requested by <%s> component", utils.StatS, utils.RadiusAgent)
}
if _, has := cfg.rpcConns[connID]; !has && !strings.HasPrefix(connID, utils.MetaInternal) {
return fmt.Errorf("<%s> connection with id: <%s> not defined", utils.RadiusAgent, connID)
}
}
for _, connID := range cfg.radiusAgentCfg.ThresholdSConns {
if strings.HasPrefix(connID, utils.MetaInternal) && !cfg.thresholdSCfg.Enabled {
return fmt.Errorf("<%s> not enabled but requested by <%s> component", utils.ThresholdS, utils.RadiusAgent)
}
if _, has := cfg.rpcConns[connID]; !has && !strings.HasPrefix(connID, utils.MetaInternal) {
return fmt.Errorf("<%s> connection with id: <%s> not defined", utils.RadiusAgent, connID)
}
}
for _, req := range cfg.radiusAgentCfg.RequestProcessors {
for _, field := range req.RequestFields {
if field.Type != utils.MetaNone && field.Path == utils.EmptyString {

200
config/radius.go Normal file
View File

@@ -0,0 +1,200 @@
/*
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 (
"slices"
"maps"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/utils"
)
// RadiusAgentCfg the config section that describes the Radius Agent
type RadiusAgentCfg struct {
Enabled bool
ListenNet string // udp or tcp
ListenAuth string
ListenAcct string
ClientSecrets map[string]string
ClientDictionaries map[string]string
SessionSConns []string
StatSConns []string
ThresholdSConns []string
RequestProcessors []*RequestProcessor
}
// loadRadiusAgentCfg loads the RadiusAgent section of the configuration
func (ra *RadiusAgentCfg) Load(ctx *context.Context, jsnCfg ConfigDB, _ *CGRConfig) (err error) {
jsnRACfg := new(RadiusAgentJsonCfg)
if err = jsnCfg.GetSection(ctx, RadiusAgentJSON, jsnRACfg); err != nil {
return
}
return ra.loadFromJSONCfg(jsnRACfg)
}
func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg) (err error) {
if jsnCfg == nil {
return nil
}
if jsnCfg.Enabled != nil {
ra.Enabled = *jsnCfg.Enabled
}
if jsnCfg.ListenNet != nil {
ra.ListenNet = *jsnCfg.ListenNet
}
if jsnCfg.ListenAuth != nil {
ra.ListenAuth = *jsnCfg.ListenAuth
}
if jsnCfg.ListenAcct != nil {
ra.ListenAcct = *jsnCfg.ListenAcct
}
maps.Copy(ra.ClientSecrets, jsnCfg.ClientSecrets)
maps.Copy(ra.ClientDictionaries, jsnCfg.ClientDictionaries)
if jsnCfg.SessionSConns != nil {
ra.SessionSConns = tagInternalConns(*jsnCfg.SessionSConns, utils.MetaSessionS)
}
if jsnCfg.StatSConns != nil {
ra.StatSConns = tagInternalConns(*jsnCfg.StatSConns, utils.MetaStats)
}
if jsnCfg.ThresholdSConns != nil {
ra.ThresholdSConns = tagInternalConns(*jsnCfg.ThresholdSConns, utils.MetaThresholds)
}
ra.RequestProcessors, err = appendRequestProcessors(ra.RequestProcessors, jsnCfg.RequestProcessors)
return
}
// AsMapInterface returns the config as a map[string]any
func (ra RadiusAgentCfg) AsMapInterface() any {
requestProcessors := make([]map[string]any, len(ra.RequestProcessors))
for i, item := range ra.RequestProcessors {
requestProcessors[i] = item.AsMapInterface()
}
mp := map[string]any{
utils.EnabledCfg: ra.Enabled,
utils.ListenNetCfg: ra.ListenNet,
utils.ListenAuthCfg: ra.ListenAuth,
utils.ListenAcctCfg: ra.ListenAcct,
utils.ClientSecretsCfg: maps.Clone(ra.ClientSecrets),
utils.ClientDictionariesCfg: maps.Clone(ra.ClientDictionaries),
utils.SessionSConnsCfg: stripInternalConns(ra.SessionSConns),
utils.StatSConnsCfg: stripInternalConns(ra.StatSConns),
utils.ThresholdSConnsCfg: stripInternalConns(ra.ThresholdSConns),
utils.RequestProcessorsCfg: requestProcessors,
}
return mp
}
func (RadiusAgentCfg) SName() string { return RadiusAgentJSON }
func (ra RadiusAgentCfg) CloneSection() Section { return ra.Clone() }
// Clone returns a deep copy of RadiusAgentCfg
func (ra RadiusAgentCfg) Clone() *RadiusAgentCfg {
clone := &RadiusAgentCfg{
Enabled: ra.Enabled,
ListenNet: ra.ListenNet,
ListenAuth: ra.ListenAuth,
ListenAcct: ra.ListenAcct,
ClientSecrets: maps.Clone(ra.ClientSecrets),
// NOTE: shallow clone and value is a slice
ClientDictionaries: maps.Clone(ra.ClientDictionaries),
SessionSConns: slices.Clone(ra.SessionSConns),
StatSConns: slices.Clone(ra.StatSConns),
ThresholdSConns: slices.Clone(ra.ThresholdSConns),
}
if ra.RequestProcessors != nil {
clone.RequestProcessors = make([]*RequestProcessor, len(ra.RequestProcessors))
for i, req := range ra.RequestProcessors {
clone.RequestProcessors[i] = req.Clone()
}
}
return clone
}
// Radius Agent configuration section
type RadiusAgentJsonCfg struct {
Enabled *bool `json:"enabled"`
ListenNet *string `json:"listen_net"`
ListenAuth *string `json:"listen_auth"`
ListenAcct *string `json:"listen_acct"`
ClientSecrets map[string]string `json:"client_secrets"`
ClientDictionaries map[string]string `json:"client_dictionaries"`
SessionSConns *[]string `json:"sessions_conns"`
StatSConns *[]string `json:"stats_conns"`
ThresholdSConns *[]string `json:"thresholds_conns"`
RequestProcessors *[]*ReqProcessorJsnCfg `json:"request_processors"`
}
func diffRadiusAgentJsonCfg(d *RadiusAgentJsonCfg, v1, v2 *RadiusAgentCfg) *RadiusAgentJsonCfg {
if d == nil {
d = new(RadiusAgentJsonCfg)
}
if v1.Enabled != v2.Enabled {
d.Enabled = utils.BoolPointer(v2.Enabled)
}
if v1.ListenNet != v2.ListenNet {
d.ListenNet = utils.StringPointer(v2.ListenNet)
}
if v1.ListenAuth != v2.ListenAuth {
d.ListenAuth = utils.StringPointer(v2.ListenAuth)
}
if v1.ListenAcct != v2.ListenAcct {
d.ListenAcct = utils.StringPointer(v2.ListenAcct)
}
d.ClientSecrets = diffMapString(d.ClientSecrets, v1.ClientSecrets, v2.ClientSecrets)
d.ClientDictionaries = diffMapString(d.ClientDictionaries, v1.ClientDictionaries, v2.ClientDictionaries)
if !slices.Equal(v1.SessionSConns, v2.SessionSConns) {
d.SessionSConns = utils.SliceStringPointer(stripInternalConns(v2.SessionSConns))
}
if !slices.Equal(v1.StatSConns, v2.StatSConns) {
d.StatSConns = utils.SliceStringPointer(stripInternalConns(v2.StatSConns))
}
if !slices.Equal(v1.ThresholdSConns, v2.ThresholdSConns) {
d.ThresholdSConns = utils.SliceStringPointer(stripInternalConns(v2.ThresholdSConns))
}
d.RequestProcessors = diffReqProcessorsJsnCfg(d.RequestProcessors, v1.RequestProcessors, v2.RequestProcessors)
return d
}
func diffMapString(d, v1, v2 map[string]string) map[string]string {
if d == nil {
d = make(map[string]string)
}
for k, v := range v2 {
if val, has := v1[k]; !has || val != v {
d[k] = v
}
}
return d
}
func diffMapStringSlice(d, v1, v2 map[string][]string) map[string][]string {
if d == nil {
d = make(map[string][]string)
}
for k, v := range v2 {
if val, has := v1[k]; !has || !slices.Equal(val, v) {
d[k] = v
}
}
return d
}

View File

@@ -28,14 +28,16 @@ import (
func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) {
cfgJSON := &RadiusAgentJsonCfg{
Enabled: utils.BoolPointer(true),
Listen_net: utils.StringPointer(utils.UDP),
Listen_auth: utils.StringPointer("127.0.0.1:1812"),
Listen_acct: utils.StringPointer("127.0.0.1:1813"),
Client_secrets: map[string]string{utils.MetaDefault: "CGRateS.org"},
Client_dictionaries: map[string]string{utils.MetaDefault: "/usr/share/cgrates/radius/dict/"},
Sessions_conns: &[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)},
Request_processors: &[]*ReqProcessorJsnCfg{
Enabled: utils.BoolPointer(true),
ListenNet: utils.StringPointer(utils.UDP),
ListenAuth: utils.StringPointer("127.0.0.1:1812"),
ListenAcct: utils.StringPointer("127.0.0.1:1813"),
ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"},
ClientDictionaries: map[string]string{utils.MetaDefault: "/usr/share/cgrates/radius/dict/"},
SessionSConns: &[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)},
StatSConns: &[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)},
ThresholdSConns: &[]string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
RequestProcessors: &[]*ReqProcessorJsnCfg{
{
ID: utils.StringPointer("OutboundAUTHDryRun"),
Filters: &[]string{"*string:~*req.request_type:OutboundAUTH", "*string:~*req.Msisdn:497700056231"},
@@ -64,6 +66,8 @@ func TestRadiusAgentCfgloadFromJsonCfgCase1(t *testing.T) {
ClientSecrets: map[string]string{utils.MetaDefault: "CGRateS.org"},
ClientDictionaries: map[string]string{utils.MetaDefault: "/usr/share/cgrates/radius/dict/"},
SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS)},
StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats)},
ThresholdSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds)},
RequestProcessors: []*RequestProcessor{
{
ID: "OutboundAUTHDryRun",
@@ -111,7 +115,7 @@ func TestRadiusAgentCfgloadFromJsonCfgCase2(t *testing.T) {
},
}`
cfgJSON := &RadiusAgentJsonCfg{
Request_processors: &[]*ReqProcessorJsnCfg{
RequestProcessors: &[]*ReqProcessorJsnCfg{
{
ID: utils.StringPointer("OutboundAUTHDryRun"),
},
@@ -136,7 +140,7 @@ func TestRadiusAgentCfgloadFromJsonCfgCase2(t *testing.T) {
func TestRadiusAgentCfgloadFromJsonCfgCase3(t *testing.T) {
cfgJSON := &RadiusAgentJsonCfg{
Request_processors: &[]*ReqProcessorJsnCfg{
RequestProcessors: &[]*ReqProcessorJsnCfg{
{
Tenant: utils.StringPointer("a{*"),
},
@@ -160,6 +164,8 @@ func TestRadiusAgentCfgAsMapInterface(t *testing.T) {
"*default": "/usr/share/cgrates/",
},
"sessions_conns": ["*birpc_internal", "*conn1","*conn2"],
"stats_conns": ["*internal", "*conn1","*conn2"],
"thresholds_conns": ["*internal", "*conn1","*conn2"],
"request_processors": [
{
"id": "OutboundAUTHDryRun",
@@ -185,7 +191,9 @@ func TestRadiusAgentCfgAsMapInterface(t *testing.T) {
utils.ClientDictionariesCfg: map[string]string{
utils.MetaDefault: "/usr/share/cgrates/",
},
utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal, "*conn1", "*conn2"},
utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal, "*conn1", "*conn2"},
utils.StatSConnsCfg: []string{utils.MetaInternal, "*conn1", "*conn2"},
utils.ThresholdSConnsCfg: []string{utils.MetaInternal, "*conn1", "*conn2"},
utils.RequestProcessorsCfg: []map[string]any{
{
utils.IDCfg: "OutboundAUTHDryRun",
@@ -223,6 +231,8 @@ func TestRadiusAgentCfgAsMapInterface1(t *testing.T) {
utils.MetaDefault: "/usr/share/cgrates/radius/dict/",
},
utils.SessionSConnsCfg: []string{"*internal"},
utils.StatSConnsCfg: []string{},
utils.ThresholdSConnsCfg: []string{},
utils.RequestProcessorsCfg: []map[string]any{},
}
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
@@ -291,6 +301,8 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
ClientSecrets: map[string]string{},
ClientDictionaries: map[string]string{},
SessionSConns: []string{"*localhost"},
StatSConns: []string{"*localhost"},
ThresholdSConns: []string{"*localhost"},
RequestProcessors: []*RequestProcessor{},
}
@@ -305,7 +317,9 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
ClientDictionaries: map[string]string{
"radius_dict1": "radius_val1",
},
SessionSConns: []string{"*birpc"},
SessionSConns: []string{"*internal"},
StatSConns: []string{"*internal"},
ThresholdSConns: []string{"*internal"},
RequestProcessors: []*RequestProcessor{
{
ID: "REQ_PROC1",
@@ -315,18 +329,20 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
}
expected := &RadiusAgentJsonCfg{
Enabled: utils.BoolPointer(true),
Listen_net: utils.StringPointer("udp"),
Listen_auth: utils.StringPointer("radius_auth2"),
Listen_acct: utils.StringPointer("radius_account2"),
Client_secrets: map[string]string{
Enabled: utils.BoolPointer(true),
ListenNet: utils.StringPointer("udp"),
ListenAuth: utils.StringPointer("radius_auth2"),
ListenAcct: utils.StringPointer("radius_account2"),
ClientSecrets: map[string]string{
"radius_user": "radius_pass",
},
Client_dictionaries: map[string]string{
ClientDictionaries: map[string]string{
"radius_dict1": "radius_val1",
},
Sessions_conns: &[]string{"*birpc"},
Request_processors: &[]*ReqProcessorJsnCfg{
SessionSConns: &[]string{"*internal"},
StatSConns: &[]string{"*internal"},
ThresholdSConns: &[]string{"*internal"},
RequestProcessors: &[]*ReqProcessorJsnCfg{
{
ID: utils.StringPointer("REQ_PROC1"),
Filters: &[]string{"filter1"},
@@ -341,9 +357,9 @@ func TestDiffRadiusAgentJsonCfg(t *testing.T) {
v1 = v2
expected = &RadiusAgentJsonCfg{
Client_secrets: map[string]string{},
Client_dictionaries: map[string]string{},
Request_processors: &[]*ReqProcessorJsnCfg{
ClientSecrets: map[string]string{},
ClientDictionaries: map[string]string{},
RequestProcessors: &[]*ReqProcessorJsnCfg{
{},
},
}
@@ -365,7 +381,9 @@ func TestRadiusAgentCloneSection(t *testing.T) {
ClientDictionaries: map[string]string{
"radius_dict1": "radius_val1",
},
SessionSConns: []string{"*birpc"},
SessionSConns: []string{"*internal"},
StatSConns: []string{"*internal"},
ThresholdSConns: []string{"*internal"},
RequestProcessors: []*RequestProcessor{
{
ID: "REQ_PROC1",
@@ -385,7 +403,9 @@ func TestRadiusAgentCloneSection(t *testing.T) {
ClientDictionaries: map[string]string{
"radius_dict1": "radius_val1",
},
SessionSConns: []string{"*birpc"},
SessionSConns: []string{"*internal"},
StatSConns: []string{"*internal"},
ThresholdSConns: []string{"*internal"},
RequestProcessors: []*RequestProcessor{
{
ID: "REQ_PROC1",

View File

@@ -1,203 +0,0 @@
/*
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 (
"slices"
"github.com/cgrates/birpc/context"
"github.com/cgrates/cgrates/utils"
)
// RadiusAgentCfg the config section that describes the Radius Agent
type RadiusAgentCfg struct {
Enabled bool
ListenNet string // udp or tcp
ListenAuth string
ListenAcct string
ClientSecrets map[string]string
ClientDictionaries map[string]string
SessionSConns []string
RequestProcessors []*RequestProcessor
}
// loadRadiusAgentCfg loads the RadiusAgent section of the configuration
func (ra *RadiusAgentCfg) Load(ctx *context.Context, jsnCfg ConfigDB, _ *CGRConfig) (err error) {
jsnRACfg := new(RadiusAgentJsonCfg)
if err = jsnCfg.GetSection(ctx, RadiusAgentJSON, jsnRACfg); err != nil {
return
}
return ra.loadFromJSONCfg(jsnRACfg)
}
func (ra *RadiusAgentCfg) loadFromJSONCfg(jsnCfg *RadiusAgentJsonCfg) (err error) {
if jsnCfg == nil {
return nil
}
if jsnCfg.Enabled != nil {
ra.Enabled = *jsnCfg.Enabled
}
if jsnCfg.Listen_net != nil {
ra.ListenNet = *jsnCfg.Listen_net
}
if jsnCfg.Listen_auth != nil {
ra.ListenAuth = *jsnCfg.Listen_auth
}
if jsnCfg.Listen_acct != nil {
ra.ListenAcct = *jsnCfg.Listen_acct
}
if jsnCfg.Client_secrets != nil {
for k, v := range jsnCfg.Client_secrets {
ra.ClientSecrets[k] = v
}
}
if jsnCfg.Client_dictionaries != nil {
for k, v := range jsnCfg.Client_dictionaries {
ra.ClientDictionaries[k] = v
}
}
if jsnCfg.Sessions_conns != nil {
ra.SessionSConns = tagInternalConns(*jsnCfg.Sessions_conns, utils.MetaSessionS)
}
ra.RequestProcessors, err = appendRequestProcessors(ra.RequestProcessors, jsnCfg.Request_processors)
return
}
// AsMapInterface returns the config as a map[string]any
func (ra RadiusAgentCfg) AsMapInterface() any {
mp := map[string]any{
utils.EnabledCfg: ra.Enabled,
utils.ListenNetCfg: ra.ListenNet,
utils.ListenAuthCfg: ra.ListenAuth,
utils.ListenAcctCfg: ra.ListenAcct,
}
requestProcessors := make([]map[string]any, len(ra.RequestProcessors))
for i, item := range ra.RequestProcessors {
requestProcessors[i] = item.AsMapInterface()
}
mp[utils.RequestProcessorsCfg] = requestProcessors
if ra.SessionSConns != nil {
mp[utils.SessionSConnsCfg] = stripInternalConns(ra.SessionSConns)
}
clientSecrets := make(map[string]string)
for k, v := range ra.ClientSecrets {
clientSecrets[k] = v
}
mp[utils.ClientSecretsCfg] = clientSecrets
clientDictionaries := make(map[string]string)
for k, v := range ra.ClientDictionaries {
clientDictionaries[k] = v
}
mp[utils.ClientDictionariesCfg] = clientDictionaries
return mp
}
func (RadiusAgentCfg) SName() string { return RadiusAgentJSON }
func (ra RadiusAgentCfg) CloneSection() Section { return ra.Clone() }
// Clone returns a deep copy of RadiusAgentCfg
func (ra RadiusAgentCfg) Clone() (cln *RadiusAgentCfg) {
cln = &RadiusAgentCfg{
Enabled: ra.Enabled,
ListenNet: ra.ListenNet,
ListenAuth: ra.ListenAuth,
ListenAcct: ra.ListenAcct,
ClientSecrets: make(map[string]string),
ClientDictionaries: make(map[string]string),
}
if ra.SessionSConns != nil {
cln.SessionSConns = slices.Clone(ra.SessionSConns)
}
for k, v := range ra.ClientSecrets {
cln.ClientSecrets[k] = v
}
for k, v := range ra.ClientDictionaries {
cln.ClientDictionaries[k] = v
}
if ra.RequestProcessors != nil {
cln.RequestProcessors = make([]*RequestProcessor, len(ra.RequestProcessors))
for i, req := range ra.RequestProcessors {
cln.RequestProcessors[i] = req.Clone()
}
}
return
}
// Radius Agent configuration section
type RadiusAgentJsonCfg struct {
Enabled *bool
Listen_net *string
Listen_auth *string
Listen_acct *string
Client_secrets map[string]string
Client_dictionaries map[string]string
Sessions_conns *[]string
Request_processors *[]*ReqProcessorJsnCfg
}
func diffRadiusAgentJsonCfg(d *RadiusAgentJsonCfg, v1, v2 *RadiusAgentCfg) *RadiusAgentJsonCfg {
if d == nil {
d = new(RadiusAgentJsonCfg)
}
if v1.Enabled != v2.Enabled {
d.Enabled = utils.BoolPointer(v2.Enabled)
}
if v1.ListenNet != v2.ListenNet {
d.Listen_net = utils.StringPointer(v2.ListenNet)
}
if v1.ListenAuth != v2.ListenAuth {
d.Listen_auth = utils.StringPointer(v2.ListenAuth)
}
if v1.ListenAcct != v2.ListenAcct {
d.Listen_acct = utils.StringPointer(v2.ListenAcct)
}
d.Client_secrets = diffMapString(d.Client_secrets, v1.ClientSecrets, v2.ClientSecrets)
d.Client_dictionaries = diffMapString(d.Client_dictionaries, v1.ClientDictionaries, v2.ClientDictionaries)
if !slices.Equal(v1.SessionSConns, v2.SessionSConns) {
d.Sessions_conns = utils.SliceStringPointer(stripInternalConns(v2.SessionSConns))
}
d.Request_processors = diffReqProcessorsJsnCfg(d.Request_processors, v1.RequestProcessors, v2.RequestProcessors)
return d
}
func diffMapString(d, v1, v2 map[string]string) map[string]string {
if d == nil {
d = make(map[string]string)
}
for k, v := range v2 {
if val, has := v1[k]; !has || val != v {
d[k] = v
}
}
return d
}
func diffMapStringSlice(d, v1, v2 map[string][]string) map[string][]string {
if d == nil {
d = make(map[string][]string)
}
for k, v := range v2 {
if val, has := v1[k]; !has || !slices.Equal(val, v) {
d[k] = v
}
}
return d
}