cfg: add conn_status_stat_queue/threshold_ids for diameter

This commit is contained in:
ionutboangiu
2025-11-12 18:11:24 +02:00
committed by Dan Christian Bogos
parent 80e645e38b
commit 22211b2b96
9 changed files with 155 additions and 91 deletions

View File

@@ -72,7 +72,9 @@ func TestDiamConnStats(t *testing.T) {
"diameter_agent": {
"enabled": true,
"stats_conns": ["*localhost"],
// "thresholds_conns": ["*localhost"]
// "thresholds_conns": ["*localhost"],
"conn_status_stat_queue_ids": ["SQ_CONN_1", "SQ_CONN_2", "SQ_CONN_3"],
// "conn_status_threshold_ids": [],
"conn_health_check_interval": "100ms"
}
}`,

View File

@@ -461,8 +461,11 @@ const (
// sendConnStatusReport reports connection status changes to StatS and ThresholdS.
func (da *DiameterAgent) sendConnStatusReport(metadata *smpeer.Metadata, status int, localAddr, remoteAddr net.Addr) {
statsConns := da.cgrCfg.DiameterAgentCfg().StatSConns
thConns := da.cgrCfg.DiameterAgentCfg().ThresholdSConns
sqIDs := da.cgrCfg.DiameterAgentCfg().ConnStatusStatQueueIDs
thIDs := da.cgrCfg.DiameterAgentCfg().ConnStatusThresholdIDs
if len(sqIDs) == 0 && len(thIDs) == 0 {
return // nothing to do
}
ev := &utils.CGREvent{
Tenant: da.cgrCfg.GeneralCfg().DefaultTenant,
@@ -480,18 +483,23 @@ func (da *DiameterAgent) sendConnStatusReport(metadata *smpeer.Metadata, status
},
}
if len(statsConns) != 0 {
if len(sqIDs) != 0 {
ev.APIOpts[utils.OptsStatsProfileIDs] = sqIDs
var reply []string
if err := da.connMgr.Call(context.TODO(), statsConns, utils.StatSv1ProcessEvent,
ev, &reply); err != nil {
if err := da.connMgr.Call(context.TODO(),
da.cgrCfg.DiameterAgentCfg().StatSConns,
utils.StatSv1ProcessEvent, ev, &reply); err != nil {
utils.Logger.Err(fmt.Sprintf("failed to process %s event in %s: %v",
utils.EventConnectionStatusReport, utils.StatS, err))
}
delete(ev.APIOpts, utils.OptsStatsProfileIDs)
}
if len(thConns) != 0 {
if len(thIDs) != 0 {
ev.APIOpts[utils.OptsThresholdsProfileIDs] = thIDs
var reply []string
if err := da.connMgr.Call(context.TODO(), thConns, utils.ThresholdSv1ProcessEvent,
ev, &reply); err != nil {
if err := da.connMgr.Call(context.TODO(),
da.cgrCfg.DiameterAgentCfg().ThresholdSConns,
utils.ThresholdSv1ProcessEvent, ev, &reply); err != nil {
utils.Logger.Err(fmt.Sprintf("failed to process %s event in %s: %v",
utils.EventConnectionStatusReport, utils.ThresholdS, err))
}

View File

@@ -1028,6 +1028,8 @@ const CGRATES_CFG_JSON = `
"asr_template": "", // enable AbortSession message being sent to client on DisconnectSession
"rar_template": "", // template used to build the Re-Auth-Request
"forced_disconnect": "*none", // the request to send to diameter on DisconnectSession <*none|*asr|*rar>
"conn_status_stat_queue_ids": [], // StatQueue IDs for connection status events
"conn_status_threshold_ids": [], // Threshold IDs for connection status events
"conn_health_check_interval": "0", // peer connection health check interval (0 to disable)
"request_processors": [] // list of processors to be applied to diameter messages
},

View File

@@ -791,6 +791,8 @@ func TestDiameterAgentJsonCfg(t *testing.T) {
SessionSConns: &[]string{rpcclient.BiRPCInternal},
StatSConns: &[]string{},
ThresholdSConns: &[]string{},
ConnStatusStatQueueIDs: &[]string{},
ConnStatusThresholdIDs: &[]string{},
OriginHost: utils.StringPointer("CGR-DA"),
OriginRealm: utils.StringPointer("cgrates.org"),
VendorID: utils.IntPointer(0),

File diff suppressed because one or more lines are too long

View File

@@ -274,6 +274,14 @@ func (cfg *CGRConfig) checkConfigSanity() error {
return fmt.Errorf("<%s> no %s connections defined",
utils.DiameterAgent, utils.SessionS)
}
if len(cfg.diameterAgentCfg.ConnStatusStatQueueIDs) != 0 && len(cfg.diameterAgentCfg.StatSConns) == 0 {
return fmt.Errorf("<%s> stat_queue_ids defined but no %s connections configured",
utils.DiameterAgent, utils.StatS)
}
if len(cfg.diameterAgentCfg.ConnStatusThresholdIDs) != 0 && len(cfg.diameterAgentCfg.ThresholdSConns) == 0 {
return fmt.Errorf("<%s> threshold_ids defined but no %s connections configured",
utils.DiameterAgent, utils.ThresholdS)
}
for _, connID := range cfg.diameterAgentCfg.SessionSConns {
isInternal := strings.HasPrefix(connID, utils.MetaInternal) || strings.HasPrefix(connID, rpcclient.BiRPCInternal)
if isInternal && !cfg.sessionSCfg.Enabled {

View File

@@ -44,6 +44,8 @@ type DiameterAgentCfg struct {
ASRTemplate string
RARTemplate string
ForcedDisconnect string
ConnStatusStatQueueIDs []string
ConnStatusThresholdIDs []string
ConnHealthCheckInterval time.Duration // peer connection health check interval (0 to disable)
RequestProcessors []*RequestProcessor
}
@@ -110,6 +112,12 @@ func (da *DiameterAgentCfg) loadFromJSONCfg(jc *DiameterAgentJsonCfg) (err error
if jc.ForcedDisconnect != nil {
da.ForcedDisconnect = *jc.ForcedDisconnect
}
if jc.ConnStatusStatQueueIDs != nil {
da.ConnStatusStatQueueIDs = *jc.ConnStatusStatQueueIDs
}
if jc.ConnStatusThresholdIDs != nil {
da.ConnStatusThresholdIDs = *jc.ConnStatusThresholdIDs
}
if jc.ConnHealthCheckInterval != nil {
da.ConnHealthCheckInterval, err = utils.ParseDurationWithNanosecs(*jc.ConnHealthCheckInterval)
if err != nil {
@@ -134,6 +142,8 @@ func (da DiameterAgentCfg) AsMapInterface() any {
utils.SessionSConnsCfg: stripInternalConns(da.SessionSConns),
utils.StatSConnsCfg: stripInternalConns(da.StatSConns),
utils.ThresholdSConnsCfg: stripInternalConns(da.ThresholdSConns),
utils.ConnStatusStatQueueIDsCfg: da.ConnStatusStatQueueIDs,
utils.ConnStatusThresholdIDsCfg: da.ConnStatusThresholdIDs,
utils.OriginHostCfg: da.OriginHost,
utils.OriginRealmCfg: da.OriginRealm,
utils.VendorIDCfg: da.VendorID,
@@ -175,6 +185,8 @@ func (da DiameterAgentCfg) Clone() *DiameterAgentCfg {
ASRTemplate: da.ASRTemplate,
RARTemplate: da.RARTemplate,
ForcedDisconnect: da.ForcedDisconnect,
ConnStatusStatQueueIDs: slices.Clone(da.ConnStatusStatQueueIDs),
ConnStatusThresholdIDs: slices.Clone(da.ConnStatusThresholdIDs),
ConnHealthCheckInterval: da.ConnHealthCheckInterval,
}
if da.CEApplications != nil {
@@ -208,6 +220,8 @@ type DiameterAgentJsonCfg struct {
ASRTemplate *string `json:"asr_template"`
RARTemplate *string `json:"rar_template"`
ForcedDisconnect *string `json:"forced_disconnect"`
ConnStatusStatQueueIDs *[]string `json:"conn_status_stat_queue_ids"`
ConnStatusThresholdIDs *[]string `json:"conn_status_threshold_ids"`
ConnHealthCheckInterval *string `json:"conn_health_check_interval"`
RequestProcessors *[]*ReqProcessorJsnCfg `json:"request_processors"`
}
@@ -264,6 +278,12 @@ func diffDiameterAgentJsonCfg(d *DiameterAgentJsonCfg, v1, v2 *DiameterAgentCfg)
if v1.ForcedDisconnect != v2.ForcedDisconnect {
d.ForcedDisconnect = utils.StringPointer(v2.ForcedDisconnect)
}
if !slices.Equal(v1.ConnStatusStatQueueIDs, v2.ConnStatusStatQueueIDs) {
d.ConnStatusStatQueueIDs = utils.SliceStringPointer(v2.ConnStatusStatQueueIDs)
}
if !slices.Equal(v1.ConnStatusThresholdIDs, v2.ConnStatusThresholdIDs) {
d.ConnStatusThresholdIDs = utils.SliceStringPointer(v2.ConnStatusThresholdIDs)
}
if v1.ConnHealthCheckInterval != v2.ConnHealthCheckInterval {
d.ConnHealthCheckInterval = utils.StringPointer(v2.ConnHealthCheckInterval.String())
}

View File

@@ -20,6 +20,7 @@ package config
import (
"reflect"
"testing"
"time"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/rpcclient"
@@ -51,22 +52,24 @@ func TestDiameterAgentCfgloadFromJsonCfg(t *testing.T) {
},
}
expected := &DiameterAgentCfg{
Enabled: true,
ListenNet: "tcp",
Listen: "127.0.0.1:3868",
DictionariesPath: "/usr/share/cgrates/diameter/dict/",
CEApplications: []string{"Base"},
SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"},
StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats), "*conn1"},
ThresholdSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), "*conn1"},
OriginHost: "CGR-DA",
OriginRealm: "cgrates.org",
VendorID: 0,
ProductName: "randomName",
SyncedConnReqs: true,
ASRTemplate: "randomTemplate",
RARTemplate: "randomTemplate",
ForcedDisconnect: "forced",
Enabled: true,
ListenNet: "tcp",
Listen: "127.0.0.1:3868",
DictionariesPath: "/usr/share/cgrates/diameter/dict/",
CEApplications: []string{"Base"},
SessionSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS), "*conn1"},
StatSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats), "*conn1"},
ThresholdSConns: []string{utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds), "*conn1"},
ConnStatusStatQueueIDs: []string{},
ConnStatusThresholdIDs: []string{},
OriginHost: "CGR-DA",
OriginRealm: "cgrates.org",
VendorID: 0,
ProductName: "randomName",
SyncedConnReqs: true,
ASRTemplate: "randomTemplate",
RARTemplate: "randomTemplate",
ForcedDisconnect: "forced",
RequestProcessors: []*RequestProcessor{
{
ID: "cgrates",
@@ -172,6 +175,8 @@ func TestDiameterAgentCfgAsMapInterface(t *testing.T) {
utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal, utils.MetaInternal, "*conn1"},
utils.StatSConnsCfg: []string{rpcclient.BiRPCInternal, utils.MetaInternal, "*conn1"},
utils.ThresholdSConnsCfg: []string{rpcclient.BiRPCInternal, utils.MetaInternal, "*conn1"},
utils.ConnStatusStatQueueIDsCfg: []string{},
utils.ConnStatusThresholdIDsCfg: []string{},
utils.SyncedConnReqsCfg: true,
utils.VendorIDCfg: 0,
utils.ConnHealthCheckIntervalCfg: "0s",
@@ -235,6 +240,8 @@ func TestDiameterAgentCfgAsMapInterface1(t *testing.T) {
utils.SessionSConnsCfg: []string{rpcclient.BiRPCInternal},
utils.StatSConnsCfg: []string{},
utils.ThresholdSConnsCfg: []string{},
utils.ConnStatusStatQueueIDsCfg: []string{},
utils.ConnStatusThresholdIDsCfg: []string{},
utils.SyncedConnReqsCfg: false,
utils.VendorIDCfg: 0,
utils.ConnHealthCheckIntervalCfg: "0s",
@@ -287,41 +294,47 @@ func TestDiffDiameterAgentJsonCfg(t *testing.T) {
var d *DiameterAgentJsonCfg
v1 := &DiameterAgentCfg{
Enabled: false,
ListenNet: "tcp",
Listen: "localhost:8080",
DictionariesPath: "/path/",
SessionSConns: []string{"*localhost"},
StatSConns: []string{"*localhost"},
ThresholdSConns: []string{"*localhost"},
OriginHost: "originHost",
OriginRealm: "originRealm",
VendorID: 2,
ProductName: "productName",
SyncedConnReqs: false,
ASRTemplate: "ASRTemplate",
RARTemplate: "RARTemplate",
ForcedDisconnect: "ForcedDisconnect",
RequestProcessors: []*RequestProcessor{},
Enabled: false,
ListenNet: "tcp",
Listen: "localhost:8080",
DictionariesPath: "/path/",
SessionSConns: []string{"*localhost"},
StatSConns: []string{"*localhost"},
ThresholdSConns: []string{"*localhost"},
OriginHost: "originHost",
OriginRealm: "originRealm",
ConnStatusStatQueueIDs: []string{"conn1", "conn2"},
ConnStatusThresholdIDs: []string{"conn1", "conn2"},
ConnHealthCheckInterval: time.Second,
VendorID: 2,
ProductName: "productName",
SyncedConnReqs: false,
ASRTemplate: "ASRTemplate",
RARTemplate: "RARTemplate",
ForcedDisconnect: "ForcedDisconnect",
RequestProcessors: []*RequestProcessor{},
}
v2 := &DiameterAgentCfg{
Enabled: true,
ListenNet: "udp",
Listen: "localhost:8037",
DictionariesPath: "/path/different",
CEApplications: []string{"Base"},
SessionSConns: []string{"*birpc_internal"},
StatSConns: []string{"*internal"},
ThresholdSConns: []string{"*internal"},
OriginHost: "diffOriginHost",
OriginRealm: "diffOriginRealm",
VendorID: 5,
ProductName: "diffProductName",
SyncedConnReqs: true,
ASRTemplate: "diffASRTemplate",
RARTemplate: "diffRARTemplate",
ForcedDisconnect: "diffForcedDisconnect",
Enabled: true,
ListenNet: "udp",
Listen: "localhost:8037",
DictionariesPath: "/path/different",
CEApplications: []string{"Base"},
SessionSConns: []string{"*birpc_internal"},
StatSConns: []string{"*internal"},
ThresholdSConns: []string{"*internal"},
OriginHost: "diffOriginHost",
OriginRealm: "diffOriginRealm",
ConnStatusStatQueueIDs: []string{"conn2", "conn3"},
ConnStatusThresholdIDs: []string{"conn2", "conn3"},
ConnHealthCheckInterval: 2 * time.Second,
VendorID: 5,
ProductName: "diffProductName",
SyncedConnReqs: true,
ASRTemplate: "diffASRTemplate",
RARTemplate: "diffRARTemplate",
ForcedDisconnect: "diffForcedDisconnect",
RequestProcessors: []*RequestProcessor{
{
ID: "id",
@@ -330,22 +343,25 @@ func TestDiffDiameterAgentJsonCfg(t *testing.T) {
}
expected := &DiameterAgentJsonCfg{
Enabled: utils.BoolPointer(true),
ListenNet: utils.StringPointer("udp"),
Listen: utils.StringPointer("localhost:8037"),
DictionariesPath: utils.StringPointer("/path/different"),
CEApplications: utils.SliceStringPointer([]string{"Base"}),
SessionSConns: &[]string{"*birpc_internal"},
StatSConns: &[]string{"*internal"},
ThresholdSConns: &[]string{"*internal"},
OriginHost: utils.StringPointer("diffOriginHost"),
OriginRealm: utils.StringPointer("diffOriginRealm"),
VendorID: utils.IntPointer(5),
ProductName: utils.StringPointer("diffProductName"),
SyncedConnRequests: utils.BoolPointer(true),
ASRTemplate: utils.StringPointer("diffASRTemplate"),
RARTemplate: utils.StringPointer("diffRARTemplate"),
ForcedDisconnect: utils.StringPointer("diffForcedDisconnect"),
Enabled: utils.BoolPointer(true),
ListenNet: utils.StringPointer("udp"),
Listen: utils.StringPointer("localhost:8037"),
DictionariesPath: utils.StringPointer("/path/different"),
CEApplications: utils.SliceStringPointer([]string{"Base"}),
SessionSConns: &[]string{"*birpc_internal"},
StatSConns: &[]string{"*internal"},
ThresholdSConns: &[]string{"*internal"},
OriginHost: utils.StringPointer("diffOriginHost"),
OriginRealm: utils.StringPointer("diffOriginRealm"),
VendorID: utils.IntPointer(5),
ProductName: utils.StringPointer("diffProductName"),
SyncedConnRequests: utils.BoolPointer(true),
ASRTemplate: utils.StringPointer("diffASRTemplate"),
RARTemplate: utils.StringPointer("diffRARTemplate"),
ForcedDisconnect: utils.StringPointer("diffForcedDisconnect"),
ConnStatusStatQueueIDs: &[]string{"conn2", "conn3"},
ConnStatusThresholdIDs: &[]string{"conn2", "conn3"},
ConnHealthCheckInterval: utils.StringPointer("2s"),
RequestProcessors: &[]*ReqProcessorJsnCfg{
{
ID: utils.StringPointer("id"),

View File

@@ -2359,6 +2359,8 @@ const (
ASRTemplateCfg = "asr_template"
RARTemplateCfg = "rar_template"
ForcedDisconnectCfg = "forced_disconnect"
ConnStatusStatQueueIDsCfg = "conn_status_stat_queue_ids"
ConnStatusThresholdIDsCfg = "conn_status_threshold_ids"
ConnHealthCheckIntervalCfg = "conn_health_check_interval"
TemplatesCfg = "templates"
RequestProcessorsCfg = "request_processors"