Skip to content

Commit

Permalink
15541 Replace BGP peer check plugin
Browse files Browse the repository at this point in the history
The Arista BGP check plugin is replaced by a more general BGP peer check plugin.

The following new features are added:
<ul>
<li>Introduction of new SNMP sections cisco_bgp_peerv2 and cisco_bgp_peerv3
<li>Add description or VrfName if available which is available as check result and service label
<li>Add established time which is available as check result aswell as a metric
<li>Move less important check output to details
<li>Add configurable state mapping for admin state and peer state
</ul>

SUP-10721

Change-Id: I3bf8f4bc92629123513a1282a5ecf6634e24829c
  • Loading branch information
loocars committed Mar 27, 2023
1 parent 7a87bf9 commit cd10a72
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 48 deletions.
21 changes: 21 additions & 0 deletions .werks/15541
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Title: Replace BGP peer check plugin
Class: feature
Compatible: compat
Component: checks
Date: 1679472169
Edition: cre
Knowledge: undoc
Level: 1
Version: 2.3.0b1

The Arista BGP check plugin is replaced by a more general BGP peer check plugin.

The following new features are added:
<ul>
<li>Introduction of new SNMP sections cisco_bgp_peerv2 and cisco_bgp_peerv3
<li>Add description or VrfName if available which is available as check result and service label
<li>Add established time which is available as check result aswell as a metric
<li>Move less important check output to details
<li>Add configurable state mapping for admin state and peer state
</ul>

16 changes: 0 additions & 16 deletions checkman/arista_bgp

This file was deleted.

19 changes: 19 additions & 0 deletions checkman/bgp_peer
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
title: BGP peer
agents: snmp
catalog: hw/network/arista
license: GPLv2
distribution: check_mk
description:
Generates service info from basic BGP information provided via SNMP (LocalAddr, LocalIdentifier,
RemoteAs, RemoteIdentifier, AdminStatus, (Peer)State, LastErrorReceivedText, EstablishedTime, Description).

The following MIBs are supported: ARISTA-BGP4V2-MIB (aristaBgp4V2Objects), CISCO-BGP4-MIB (cbgpPeer2Entry, cbgpPeer3Entry)

By default the check result is always OK but the AdminStatus and PeerState can be remapped to different states
via configuration.

item:
One service is created for remote IP address

discovery:
One service identified
155 changes: 135 additions & 20 deletions cmk/base/plugins/agent_based/bgp_peer.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,19 @@
"""

from typing import List, Mapping, NamedTuple
from typing import List, Mapping, NamedTuple, TypedDict

from .agent_based_api.v1 import (
all_of,
exists,
Metric,
OIDBytes,
OIDEnd,
register,
render,
Result,
Service,
ServiceLabel,
SNMPTree,
startswith,
State,
Expand All @@ -117,13 +122,42 @@ class BGPData(NamedTuple):
admin_state: str
peer_state: str
last_received_error: str
established_time: int
description: str
bgp_version: int


Section = Mapping[str, BGPData]

AdminStateMapping = Mapping[str, int]
PeerStateMapping = Mapping[str, int]

def parse_arista_bgp(string_table: List[StringByteTable]) -> Section:

class BGPPeerParams(TypedDict):
admin_state_mapping: AdminStateMapping
peer_state_mapping: PeerStateMapping


DEFAULT_ADMIN_STATE_MAPPING: AdminStateMapping = {
"halted": 0,
"running": 0,
}

DEFAULT_PEER_STATE_MAPPING: PeerStateMapping = {
"idle": 0,
"active": 0,
"opensent": 0,
"openconfirm": 0,
"established": 0,
}

DEFAULT_BGP_PEER_PARAMS = BGPPeerParams(
admin_state_mapping=DEFAULT_ADMIN_STATE_MAPPING,
peer_state_mapping=DEFAULT_PEER_STATE_MAPPING,
)


def parse_bgp_peer(string_table: List[StringByteTable]) -> Section:
def convert_address(value: str | list[int]) -> str:
if not value:
return "empty()"
Expand Down Expand Up @@ -155,6 +189,10 @@ def create_item_data(entry: list[str | list[int]]) -> BGPData:
"6": "established",
}.get(entry[5] if isinstance(entry[5], str) else "0", "unknown(%r)" % entry[5]),
last_received_error=entry[6] if isinstance(entry[6], str) else "unknown(%r)" % entry[6],
established_time=int(entry[7]) if isinstance(entry[7], str) else 0,
description=(entry[-2] if isinstance(entry[-2], str) else "unknown(%r)" % entry[-2])
if len(entry) > len(BGPData.__annotations__) - 1
else "n/a",
bgp_version=4,
)

Expand All @@ -177,39 +215,60 @@ def remote_addr(oid_end: str) -> str:
)

assert all(
len(entry) == len(BGPData.__annotations__) for entry in string_table[0]
len(entry) >= len(BGPData.__annotations__) - 1 for entry in string_table[0]
), "Not all info elements have the size guessed from known names %d: %r" % (
len(BGPData.__annotations__),
[len(entry) for entry in string_table[0]],
)
return {remote_addr(str(entry[-1])): create_item_data(entry) for entry in string_table[0]}


def discover_arista_bgp(section: Section) -> DiscoveryResult:
yield from (Service(item=item) for item in section)
def discover_bgp_peer(section: Section) -> DiscoveryResult:
yield from (
Service(item=item, labels=[ServiceLabel("cmk/bgp/description", peer.description)])
for item, peer in section.items()
)


def check_arista_bgp(
def check_bgp_peer(
item: str,
params: BGPPeerParams,
section: Section,
) -> CheckResult:
if not (peer := section.get(item)):
return
yield Result(state=State.OK, summary=f"Description: {peer.description!r}")
yield Result(state=State.OK, summary=f"Local address: {peer.local_address!r}")
yield Result(state=State.OK, summary=f"Local identifier: {peer.local_identifier!r}")
yield Result(state=State.OK, summary=f"Remote AS number: {peer.remote_as_number}")
yield Result(state=State.OK, summary=f"Remote identifier: {peer.remote_identifier!r}")
yield Result(state=State.OK, summary=f"Admin state: {peer.admin_state!r}")
yield Result(state=State.OK, summary=f"Peer state: {peer.peer_state!r}")
yield Result(state=State.OK, summary=f"Last received error: {peer.last_received_error!r}")
yield Result(state=State.OK, summary=f"BGP version: {peer.bgp_version}")
yield Result(state=State.OK, summary=f"Remote address: {item!r}")
yield Result(
state=State(
params.get("admin_state_mapping", DEFAULT_ADMIN_STATE_MAPPING).get(peer.admin_state, 3)
),
summary=f"Admin state: {peer.admin_state!r}",
)
yield Result(
state=State(
params.get("peer_state_mapping", DEFAULT_PEER_STATE_MAPPING).get(peer.peer_state, 3)
),
summary=f"Peer state: {peer.peer_state!r}",
)
yield Result(
state=State.OK, summary=f"Established time: {render.timespan(peer.established_time)}"
)
yield Result(state=State.OK, notice=f"Local identifier: {peer.local_identifier!r}")
yield Result(state=State.OK, notice=f"Remote identifier: {peer.remote_identifier!r}")
yield Result(state=State.OK, notice=f"Remote AS number: {peer.remote_as_number}")
yield Result(state=State.OK, notice=f"Last received error: {peer.last_received_error!r}")
yield Result(state=State.OK, notice=f"BGP version: {peer.bgp_version}")
yield Result(state=State.OK, notice=f"Remote address: {item!r}")

yield Metric("uptime", peer.established_time)


register.snmp_section(
name="arista_bgp_peer",
parse_function=parse_arista_bgp,
parsed_section_name="arista_bgp",
parse_function=parse_bgp_peer,
parsed_section_name="bgp_peer",
supersedes=["arista_bgp"],
fetch=[
SNMPTree(
base=".1.3.6.1.4.1.30065.4.1.1", # ARISTA-BGP4V2-MIB::aristaBgp4V2Objects
Expand All @@ -221,16 +280,72 @@ def check_arista_bgp(
"2.1.12", # AdminStatus
"2.1.13", # State
"3.1.4", # LastErrorReceivedTex
"4.1.1", # FsmEstablishedTime
"2.1.14", # Description
OIDEnd(), # RemoteAddr
],
)
],
detect=startswith(".1.3.6.1.2.1.1.1.0", "arista networks"),
detect=startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.30065"),
)

register.snmp_section(
name="cisco_bgp_peerv2",
parse_function=parse_bgp_peer,
parsed_section_name="bgp_peer",
fetch=[
SNMPTree(
base=".1.3.6.1.4.1.9.9.187.1.2.5.1", # CISCO-BGP4-MIB::cbgpPeer2Entry
oids=[
OIDBytes("6"), # cbgpPeer2LocalAddr
"9", # cbgpPeer2LocalIdentifier
"11", # cbgpPeer2RemoteAs
"12", # cbgpPeer2RemoteIdentifier
"4", # cbgpPeer2AdminStatus
"3", # cbgpPeer2State
"28", # cbgpPeer2LastErrorTxt
"19", # cbgpPeer2FsmEstablishedTime
OIDEnd(), # cbgpPeer2RemoteAddr
],
)
],
detect=all_of(
startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.9.1.2818"),
exists(".1.3.6.1.4.1.9.9.187.1.2.5.1.*"),
),
)
register.snmp_section(
name="cisco_bgp_peerv3",
parse_function=parse_bgp_peer,
parsed_section_name="bgp_peer",
fetch=[
SNMPTree(
base=".1.3.6.1.4.1.9.9.187.1.2.9.1", # CISCO-BGP4-MIB::cbgpPeer3Entry
oids=[
OIDBytes("8"), # cbgpPeer3LocalAddr
"11", # cbgpPeer3LocalIdentifier
"13", # cbgpPeer3RemoteAs
"14", # cbgpPeer3RemoteIdentifier
"6", # cbgpPeer3AdminStatus
"5", # cbgpPeer3State
"30", # cbgpPeer3LastErrorTxt
"21", # cbgpPeer3FsmEstablishedTime
"4", # cbgpPeer3VrfName
OIDEnd(), # cbgpPeer3RemoteAddr
],
)
],
detect=all_of(
startswith(".1.3.6.1.2.1.1.2.0", ".1.3.6.1.4.1.9.1.2818"),
exists(".1.3.6.1.4.1.9.9.187.1.2.9.1.*"),
),
)

register.check_plugin(
name="arista_bgp",
name="bgp_peer",
service_name="BGP Peer %s",
discovery_function=discover_arista_bgp,
check_function=check_arista_bgp,
discovery_function=discover_bgp_peer,
check_function=check_bgp_peer,
check_ruleset_name="bgp_peer",
check_default_parameters=DEFAULT_BGP_PEER_PARAMS,
)
55 changes: 55 additions & 0 deletions cmk/gui/plugins/wato/check_parameters/bgp_peer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env python3
# Copyright (C) 2019 tribe29 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.gui.i18n import _
from cmk.gui.plugins.wato.utils import (
CheckParameterRulespecWithItem,
rulespec_registry,
RulespecGroupCheckParametersNetworking,
)
from cmk.gui.valuespec import Dictionary, MonitoringState


def _parameter_valuespec_bgp_peer():
return Dictionary(
elements=[
(
"admin_state_mapping",
Dictionary(
title=_("Admin States"),
elements=[
("halted", MonitoringState(title="halted")),
("running", MonitoringState(title="running")),
],
optional_keys=[],
),
),
(
"peer_state_mapping",
Dictionary(
title=_("Peer States"),
elements=[
("idle", MonitoringState(title="idle")),
("active", MonitoringState(title="active")),
("opensent", MonitoringState(title="opensent")),
("openconfirm", MonitoringState(title="openconfirm")),
("established", MonitoringState(title="established")),
],
optional_keys=[],
),
),
],
)


rulespec_registry.register(
CheckParameterRulespecWithItem(
check_group_name="bgp_peer",
group=RulespecGroupCheckParametersNetworking,
match_type="dict",
parameter_valuespec=_parameter_valuespec_bgp_peer,
title=lambda: _("BGP Peer State Mapping"),
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@
CheckPluginName("jolokia_metrics_gc"): CheckPluginName("jolokia_jvm_garbagecollectors"),
CheckPluginName("ups_power"): CheckPluginName("epower"),
CheckPluginName("esx_vsphere_counters"): CheckPluginName("esx_vsphere_datastore_io"),
CheckPluginName("arista_bgp"): CheckPluginName("bgp_peer"),
}
Loading

0 comments on commit cd10a72

Please sign in to comment.