Skip to content

Commit

Permalink
AudioCodes SBC Calls: Introduce new check plugin
Browse files Browse the repository at this point in the history
CMK-20166

Change-Id: I16ccce1c2d017aac9360938999fe2576818e69be
  • Loading branch information
racicLuka committed Dec 3, 2024
1 parent d277d6e commit 602b8fa
Show file tree
Hide file tree
Showing 8 changed files with 433 additions and 2 deletions.
5 changes: 3 additions & 2 deletions cmk/plugins/audiocodes/agent_based/alarms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from cmk.agent_based.v2 import (
CheckPlugin,
CheckResult,
contains,
DiscoveryResult,
render,
Result,
Expand All @@ -21,6 +20,8 @@
StringTable,
)

from .lib import DETECT_AUDIOCODES

_READABLE_SEVERITY = {
"0": "cleared",
"1": "indeterminate",
Expand Down Expand Up @@ -86,7 +87,7 @@ def parse_audiocodes_alarms(string_table: Sequence[StringTable]) -> Section | No

snmp_section_audiocodes_alarms = SNMPSection(
name="audiocodes_alarms",
detect=contains(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.5003.8.1.1"),
detect=DETECT_AUDIOCODES,
fetch=[
SNMPTree(
base=".1.3.6.1.4.1.5003.11.1.1.1.1",
Expand Down
162 changes: 162 additions & 0 deletions cmk/plugins/audiocodes/agent_based/calls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

import time
from collections.abc import Mapping, MutableMapping, Sequence
from dataclasses import dataclass
from typing import Any

from cmk.agent_based.v2 import (
check_levels,
CheckPlugin,
CheckResult,
DiscoveryResult,
FixedLevelsT,
get_rate,
get_value_store,
NoLevelsT,
render,
Service,
SNMPSection,
SNMPTree,
StringTable,
)

from .lib import DETECT_AUDIOCODES


@dataclass(frozen=True, kw_only=True)
class Calls:
active_calls: int
total_calls: int
average_success_ratio: int
average_call_duration: int
active_calls_in: int | None = None
active_calls_out: int | None = None


def parse_audiocodes_calls(string_table: Sequence[StringTable]) -> Calls | None:
return (
Calls(
active_calls=int(line[0][0]),
total_calls=int(line[0][1]),
average_success_ratio=int(line[0][2]),
average_call_duration=int(line[0][3]),
active_calls_in=int(string_table[1][0][0]) if string_table[1] else None,
active_calls_out=int(string_table[1][0][1]) if string_table[1] else None,
)
if string_table[0] and (line := string_table[0])
else None
)


snmp_section_audiocodes_alarms = SNMPSection(
name="audiocodes_calls",
detect=DETECT_AUDIOCODES,
fetch=[
SNMPTree(
base=".1.3.6.1.4.1.5003.10.8.2",
oids=[
"52.43.1.2.0", # AC-PM-Control-MIB::acPMSIPSBCEstablishedCallsVal.0
"52.43.1.9.0", # AC-PM-Control-MIB::acPMSIPSBCEstablishedCallsTotal.0
"54.49.1.2.0", # AC-PM-Control-MIB::acPMSBCAsrVal.0
"54.52.1.2.0", # AC-PM-Control-MIB::acPMSBCAcdVal.0
],
),
SNMPTree(
base=".1.3.6.1.4.1.5003.15.3.1.1.1",
oids=[
"2", # acKpiSbcCallStatsCurrentGlobalActiveCallsIn
"3", # acKpiSbcCallStatsCurrentGlobalActiveCallsOut
],
),
],
parse_function=parse_audiocodes_calls,
)


def discover_audiocodes_calls(section: Calls) -> DiscoveryResult:
yield Service()


def check_audiocodes_calls(
params: Mapping[str, NoLevelsT | FixedLevelsT], section: Calls
) -> CheckResult:
yield from check_audiocodes_calls_testable(
params=params,
section=section,
now=time.time(),
value_store=get_value_store(),
)


def check_audiocodes_calls_testable(
*,
params: Mapping[str, NoLevelsT | FixedLevelsT],
section: Calls,
now: float,
value_store: MutableMapping[str, Any],
) -> CheckResult:
yield from check_levels(
value=section.active_calls,
label="Active Calls",
metric_name="audiocodes_active_calls",
)

call_rate = get_rate(
value_store,
"total_calls",
now,
section.total_calls,
)
yield from check_levels(
value=call_rate,
label="Calls per Second",
metric_name="audiocodes_calls_per_sec",
render_func=lambda x: f"{x:.2f}/s",
)

yield from check_levels(
value=section.average_success_ratio,
levels_lower=params.get("asr_lower_levels"),
render_func=render.percent,
label="Average Succes Ratio",
metric_name="audiocodes_average_success_ratio",
)

yield from check_levels(
value=section.average_call_duration,
label="Average Call Duration",
metric_name="audiocodes_average_call_duration",
render_func=render.timespan,
)

if section.active_calls_in is not None:
yield from check_levels(
value=section.active_calls_in,
label="Active Calls In",
metric_name="audiocodes_active_calls_in",
notice_only=True,
)

if section.active_calls_out is not None:
yield from check_levels(
value=section.active_calls_out,
label="Active Calls Out",
metric_name="audiocodes_active_calls_out",
notice_only=True,
)


check_plugin_audiocodes_calls = CheckPlugin(
name="audiocodes_calls",
service_name="AudioCodes SBC Calls",
discovery_function=discover_audiocodes_calls,
check_function=check_audiocodes_calls,
check_ruleset_name="audiocodes_calls",
check_default_parameters={
"asr_lower_levels": ("no_levels", None),
},
)
9 changes: 9 additions & 0 deletions cmk/plugins/audiocodes/agent_based/lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.


from cmk.agent_based.v2 import contains

DETECT_AUDIOCODES = contains(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.5003.8.1.1")
10 changes: 10 additions & 0 deletions cmk/plugins/audiocodes/checkman/audiocodes_calls
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
title: AudioCodes: SBC Calls
agents: snmp
catalog: agentless
license: GPLv2
distribution: check_mk
description:
This check plugin monitors the SBC Calls of the AudioCodes device.

discovery:
One service is created.
56 changes: 56 additions & 0 deletions cmk/plugins/audiocodes/graphing/calls_in_out.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

from cmk.graphing.v1 import graphs, metrics, perfometers, Title

UNIT_COUNT = metrics.Unit(metrics.DecimalNotation(""))


metric_audiocodes_active_calls_in = metrics.Metric(
name="audiocodes_active_calls_in",
title=Title("Active Calls In"),
unit=UNIT_COUNT,
color=metrics.Color.GREEN,
)

metric_audiocodes_active_calls_out = metrics.Metric(
name="audiocodes_active_calls_out",
title=Title("Active Calls Out"),
unit=UNIT_COUNT,
color=metrics.Color.LIGHT_GREEN,
)

graph_audiocodes_calls_in_out = graphs.Bidirectional(
name="audiocodes_calls_in_out",
title=Title("Calls In/Out"),
lower=graphs.Graph(
name="audiocodes_calls_out",
title=Title("Calls Out"),
compound_lines=[
"audiocodes_active_calls_out",
],
),
upper=graphs.Graph(
name="audiocodes_calls_in",
title=Title("Calls In"),
compound_lines=[
"audiocodes_active_calls_in",
],
),
)

perfometer_audiocodes_calls_in_out = perfometers.Bidirectional(
name="audiocodes_calls_in_out",
right=perfometers.Perfometer(
name="audiocodes_active_calls_out",
focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(1000)),
segments=["audiocodes_active_calls_out"],
),
left=perfometers.Perfometer(
name="audiocodes_active_calls_in",
focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(1000)),
segments=["audiocodes_active_calls_in"],
),
)
40 changes: 40 additions & 0 deletions cmk/plugins/audiocodes/graphing/calls_standalone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

from cmk.graphing.v1 import metrics, Title

UNIT_PERCENTAGE = metrics.Unit(metrics.DecimalNotation("%"))
UNIT_COUNT = metrics.Unit(metrics.DecimalNotation(""))
UNIT_PER_SECOND = metrics.Unit(metrics.DecimalNotation("/s"))
UNIT_SECOND = metrics.Unit(metrics.TimeNotation())


metric_audiocodes_active_calls = metrics.Metric(
name="audiocodes_active_calls",
title=Title("Active Calls"),
unit=UNIT_COUNT,
color=metrics.Color.BLUE,
)

metric_audiocodes_calls_per_sec = metrics.Metric(
name="audiocodes_calls_per_sec",
title=Title("Calls per Second"),
unit=UNIT_PER_SECOND,
color=metrics.Color.DARK_BLUE,
)

metric_audiocodes_average_success_ratio = metrics.Metric(
name="audiocodes_average_success_ratio",
title=Title("Average Success Ratio"),
unit=UNIT_PERCENTAGE,
color=metrics.Color.YELLOW,
)

metric_audiocodes_average_call_duration = metrics.Metric(
name="audiocodes_average_call_duration",
title=Title("Average Call Duration"),
unit=UNIT_SECOND,
color=metrics.Color.PURPLE,
)
39 changes: 39 additions & 0 deletions cmk/plugins/audiocodes/rulesets/calls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.
from cmk.rulesets.v1 import Title
from cmk.rulesets.v1.form_specs import (
DictElement,
Dictionary,
InputHint,
LevelDirection,
Percentage,
SimpleLevels,
)
from cmk.rulesets.v1.rule_specs import CheckParameters, HostCondition, Topic


def _parameter_form_audiocores_calls() -> Dictionary:
return Dictionary(
elements={
"asr_lower_levels": DictElement(
required=True,
parameter_form=SimpleLevels(
title=Title("Lower levels for average success ratio"),
form_spec_template=Percentage(),
level_direction=LevelDirection.LOWER,
prefill_fixed_levels=InputHint((80.0, 70.0)),
),
)
}
)


rule_spec_audiocodes_calls = CheckParameters(
name="audiocodes_calls",
topic=Topic.APPLICATIONS,
parameter_form=_parameter_form_audiocores_calls,
title=Title("AudioCodes SBC Calls"),
condition=HostCondition(),
)
Loading

0 comments on commit 602b8fa

Please sign in to comment.