diff --git a/README.md b/README.md index 424b923622e7a903c0b4e2704d606e956ce69b5a..66e44bc650184f1fc7d230c59d93c4e49dc5d856 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/bgp_peer-2.2.8-20250117.mkp "bgp_peer-2.2.8-20250117.mkp" +[PACKAGE]: ../../raw/master/mkp/bgp_peer-2.3.0-20250329.mkp "bgp_peer-2.3.0-20250329.mkp" # BGP Peer Check plugin to monitor the status of BGP peers and inventory plugin for static BGP peer data. diff --git a/mkp/bgp_peer-2.3.0-20250329.mkp b/mkp/bgp_peer-2.3.0-20250329.mkp new file mode 100644 index 0000000000000000000000000000000000000000..e3f51db18d304f8228fdfbd54a2c2c9c0632aed8 Binary files /dev/null and b/mkp/bgp_peer-2.3.0-20250329.mkp differ diff --git a/source/agent_based/bgp_peer.py b/source/agent_based/bgp_peer.py index df8172bb410fdfcae76032a51ff6e20a28d07f4a..32f65c748919a875f8cf287f2a544783f79da38d 100644 --- a/source/agent_based/bgp_peer.py +++ b/source/agent_based/bgp_peer.py @@ -1,328 +1,2 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# License: GNU General Public License v2 - -# Author: thl-cmk[at]outlook[dot]com -# URL : https://thl-cmk.hopto.org -# Date : 2021-08-20 - -# based on the BGP peer plugin by Thomas Wollner (tw@wollner-net.de) -# -# 2021-08-20: rewritten for CMK 2.0 by thl-cmk[at]outlook[dot]com -# 2021-08-21: added more perfdata, added metrics file -# 2021-08-22: added WATO options, streamlined with cisco_bgp_peer -# 2021-08-29: moved static (longoutput) to inventory plugin -# moved helper functions to utils/bgp_peer -# 2021-11-14: merged check function with cisco_bgp_peer -# moved parse function to utils/bgp_peer -# 2021-04-02: rewritten bgp neighbor state handling (made configurable) -# 2022-04-29: added upper/lower prefix limits from wato -# added info if device is admin prefix limit capable (device_admin_limit) -# 2022-05-09: made item name configurable (don't use address-family/routing-instance/VRF) -# 2022-05-11: changed bgp_get_peer_entry to get proper parameters instead of Nontransparent list -# added remote_as to BgpPeerItem -# 2022-09-05: added missing wato parameters to register.check_plugin check_default_parameters -# 2022-09-10: made more reliable on limited data (fsm_established_time and admin_state) -# (THX to martin[dot]pechstein[at]posteo[dot]de) -# 2022-09-11: optimized internal flow: > alias > not found > admin down > peer state > ... -# 2023-01-21: changed to always yield fsm_established_time (not only if beep connects, but also on all other states) -# 2023-01-22: fix output for admin_state -# 2023-02-16: changed for CMK 2.1 (moved gui files from local/share/.. to local/lib/..) -# fix type error in discovery (CMK2.1 GUI only) -# 2023-02-20: fix crash if metric data is None -# 2023-03-26: optimized output of metrics, GetRateError will not be set to 0 anymore -# 2023-08-17: fix removed internal_item form check_default_parameters (THX mail[at]bastian-kuhn[dot]de) -# added warning if internal_item is missing in params -# 2024-06-07: fixed crash on configured state mapping -# 2024-12-20: added local address/as/identifier for bgp_topology - -# Example Agent Output: -# BGP4-MIB - -# .1.3.6.1.2.1.15.3.1.1.192.168.254.2 = IpAddress: 192.168.254.2 -# .1.3.6.1.2.1.15.3.1.2.192.168.254.2 = INTEGER: 3 -# .1.3.6.1.2.1.15.3.1.3.192.168.254.2 = INTEGER: 2 -# .1.3.6.1.2.1.15.3.1.4.192.168.254.2 = INTEGER: 4 -# .1.3.6.1.2.1.15.3.1.5.192.168.254.2 = IpAddress: 0.0.0.0 -# .1.3.6.1.2.1.15.3.1.7.192.168.254.2 = IpAddress: 192.168.254.2 -# .1.3.6.1.2.1.15.3.1.9.192.168.254.2 = INTEGER: 65301 -# .1.3.6.1.2.1.15.3.1.10.192.168.254.2 = Counter32: 0 -# .1.3.6.1.2.1.15.3.1.11.192.168.254.2 = Counter32: 5 -# .1.3.6.1.2.1.15.3.1.14.192.168.254.2 = Hex-STRING: 04 00 -# .1.3.6.1.2.1.15.3.1.16.192.168.254.2 = Gauge32: 6586822 -# - -import time -from typing import Dict, List - -from cmk.base.plugins.agent_based.agent_based_api.v1 import ( - register, - Service, - Result, - check_levels, - State, - SNMPTree, - exists, - get_rate, - GetRateError, - get_value_store, - # IgnoreResultsError, - Metric, - render, -) -from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( - DiscoveryResult, - CheckResult, - StringTable, -) -from cmk.base.plugins.agent_based.utils.bgp_peer import ( - BgpPeer, - bgp_get_peer_entry, - bgp_adminstate, - bgp_peerstate, -) - - -def parse_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer] | None: - peer_table = {} - try: - peer_info, local_info = string_table - except ValueError: - return - - try: - local_as, local_id = local_info[0] - except (IndexError, ValueError): - local_as, local_id = None, None - - for entry in peer_info: - remote_addr, remote_id, peer_state, admin_state, local_addr, remote_as, in_updates, out_updates, \ - in_messages, out_messages, fsm_established_transitions, fsm_established_time, in_update_elapsed_time = entry - - bgp_peer = bgp_get_peer_entry( - admin_state=admin_state, - fsm_established_time=fsm_established_time, - fsm_established_transitions=fsm_established_transitions, - in_messages=in_messages, - in_update_elapsed_time=in_update_elapsed_time, - in_updates=in_updates, - local_addr=local_addr, - out_messages=out_messages, - out_updates=out_updates, - peer_state=peer_state, - remote_addr=remote_addr, - remote_as=remote_as, - remote_id=remote_id, - local_as=local_as, - local_id=local_id, - ) - if bgp_peer: - peer_table.update(bgp_peer) - return peer_table - - -def discovery_bgp_peer(params, section: Dict[str, BgpPeer]) -> DiscoveryResult: - _item_parts = [ - 'remote_address', - 'remote_as', - 'address_family', - 'routing_instance', - ] - for key in section.keys(): - parameters = {'internal_item': key} - item = '' - for item_part in _item_parts: - if item_part not in params['build_item']: - item += f'{section[key].item[item_part]} ' - item = item.strip(' ') - yield Service(item=item, parameters=parameters) - - -def bgp_peer_base_info(peer: BgpPeer) -> GeneratorExit: - for message, value in [ - ('Local AS:', peer.local_as), - ('Local address:', peer.local_addr), - ('Local identifier:', peer.local_id), - ('Remote AS:', peer.remote_as), - ('Remote address:', peer.remote_addr), - ('Remote identifier:', peer.remote_id), - ]: - if value is not None: - yield Result(state=State.OK, notice=f'{message} {value}') - - -def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult: - if not params.get('internal_item'): - yield Result( - state=State.WARN, - summary='This service is using old parameters (see details)', - details='This service is using old parameters. To refresh the parameters you need to do a "Tabula rasa" ' - '(Discover services -> Remove all and find new)', - ) - else: - item = params['internal_item'] - - neighborstate = { - '1': 2, # idle - '2': 1, # connect - '3': 1, # active - '4': 1, # opensent - '5': 1, # openconfirm - '6': 0, # established - } - - neighborstate.update(params['neighborstate']) - peer_not_found_state = params['peernotfound'] - - for bgp_connection, bgp_alias, not_found_state in params.get('peer_list', []): - if item == bgp_connection: - if bgp_alias != '': - yield Result(state=State.OK, summary=f'[{bgp_alias}]', details=' ') - peer_not_found_state = not_found_state - - # get item data - try: - peer = section[item] - except KeyError: - yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data') - return - - if peer.description: - yield Result(state=State.OK, summary=f'[{peer.description}]', details=' ') - - if peer.admin_state == 1: # shutdown - yield Result(state=State(params['admindown']), summary=f'Admin state: {bgp_adminstate(peer.admin_state)}') - yield from bgp_peer_base_info(peer) - return - - yield Result( - state=State(neighborstate.get(str(peer.peer_state))), - notice=f'Peer state: {bgp_peerstate(peer.peer_state)}' - ) - - if peer.fsm_established_time: # always yield fsm_established time - yield Metric( - name=f'bgp_peer_fsmestablishedtime', - value=peer.fsm_established_time, - boundaries=(0, None) - ) - - if not peer.peer_state == 6: # not established - yield from bgp_peer_base_info(peer) - return - - if peer.fsm_established_time: # if peer is established use fsm_established_time as uptime - yield from check_levels( - value=peer.fsm_established_time, - label='Uptime', - levels_lower=params['minuptime'], - render_func=render.timespan, - metric_name='bgp_peer_fsmestablishedtime', - ) - - if peer.peer_unavail_reason != 0: # huawei peer unavailable state - yield Result(state=State.CRIT, notice=F'Peer unavailable reason: {peer.peer_unavail_reason_str}') - - if peer.device_admin_limit and peer.prefix_admin_limit is None: - yield Result( - state=State(params['noprefixlimit']), - notice='Prefix limit/warn threshold not configured on the device.', - ) - - acceptedprefixes = peer.accepted_prefixes - prefixadminlimit = peer.prefix_admin_limit - prefixthreshold = peer.prefix_threshold - warnthreshold = None - - if prefixadminlimit is not None and prefixthreshold is not None: - warnthreshold = int(prefixadminlimit / 100.0 * prefixthreshold) # use float (100.0) to get xx.xx in division - if acceptedprefixes is not None and peer.peer_state == 6: # peer established and prefixes accepted - yield from check_levels( - value=acceptedprefixes, - metric_name='bgp_peer_acceptedprefixes', - levels_upper=params.get('accepted_prefixes_upper_levels', (warnthreshold, prefixadminlimit)), - levels_lower=params.get('accepted_prefixes_lower_levels'), - label='Prefixes accepted', - render_func=lambda v: f'{v}' - ) - - now_time = time.time() - value_store = get_value_store() - - for key, value in peer.metric_rate: - try: - value = get_rate(value_store, f'{key}', now_time, value, raise_overflow=True) - except GetRateError: - continue - yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None)) - - for key, value in peer.metric_count: - if value is not None: - yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None)) - - yield from bgp_peer_base_info(peer) - - -register.snmp_section( - name='bgp_peer', - parse_function=parse_bgp_peer, - fetch=[ - SNMPTree( - base='.1.3.6.1.2.1.15.3.1', # BGP4-MIB::BgpPeerEntry - oids=[ - '7', # bgpPeerRemoteAddr - '1', # bgpPeerIdentifier - '2', # bgpPeerState - '3', # bgpPeerAdminStatus - '5', # bgpPeerLocalAddr - '9', # bgpPeerRemoteAs - '10', # bgpPeerInUpdates - '11', # bgpPeerOutUpdates - '12', # bgpPeerInTotalMessages - '13', # bgpPeerOutTotalMessages - '15', # bgpPeerFsmEstablishedTransitions - '16', # bgpPeerFsmEstablishedTime - '24', # bgpPeerInUpdateElapsedTime - ]), - SNMPTree( - base='.1.3.6.1.2.1.15', # BGP4-MIB - oids=[ - '2', # bgpLocalAs - '4', # bgpIdentifier (local) - ]) - ], - detect=exists('.1.3.6.1.2.1.15.3.1.1.*') -) - -register.check_plugin( - name='bgp_peer', - service_name='BGP peer %s', - discovery_function=discovery_bgp_peer, - discovery_default_parameters={ - 'build_item': [ - # 'remote_address', - 'remote_as', - # 'address_family', - # 'routing_instance', - ] - }, - discovery_ruleset_name='discovery_bgp_peer', - check_function=check_bgp_peer, - check_default_parameters={ - 'minuptime': (7200, 3600), - 'peer_list': [], - 'peernotfound': 2, - 'admindown': 1, - 'noprefixlimit': 1, - 'neighborstate': { - '1': 2, # idle - '2': 1, # connect - '3': 1, # active - '4': 1, # opensent - '5': 1, # openconfirm - '6': 0, # established - }, - }, - check_ruleset_name='bgp_peer', -) +# dummy needed for CMK 2.30x to shadow the original file \ No newline at end of file diff --git a/source/cmk_addons_plugins/bgp_peer/agent_based/bgp_peer.py b/source/cmk_addons_plugins/bgp_peer/agent_based/bgp_peer.py new file mode 100644 index 0000000000000000000000000000000000000000..e2f29fec27e9599df2c56015f8315c450a640aed --- /dev/null +++ b/source/cmk_addons_plugins/bgp_peer/agent_based/bgp_peer.py @@ -0,0 +1,352 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# License: GNU General Public License v2 + +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2021-08-20 + +# based on the BGP peer plugin by Thomas Wollner (tw@wollner-net.de) +# +# 2021-08-20: rewritten for CMK 2.0 by thl-cmk[at]outlook[dot]com +# 2021-08-21: added more perfdata, added metrics file +# 2021-08-22: added WATO options, streamlined with cisco_bgp_peer +# 2021-08-29: moved static (longoutput) to inventory plugin +# moved helper functions to utils/bgp_peer +# 2021-11-14: merged check function with cisco_bgp_peer +# moved parse function to utils/bgp_peer +# 2021-04-02: rewritten bgp neighbor state handling (made configurable) +# 2022-04-29: added upper/lower prefix limits from wato +# added info if device is admin prefix limit capable (device_admin_limit) +# 2022-05-09: made item name configurable (don't use address-family/routing-instance/VRF) +# 2022-05-11: changed bgp_get_peer_entry to get proper parameters instead of Nontransparent list +# added remote_as to BgpPeerItem +# 2022-09-05: added missing wato parameters to register.check_plugin check_default_parameters +# 2022-09-10: made more reliable on limited data (fsm_established_time and admin_state) +# (THX to martin[dot]pechstein[at]posteo[dot]de) +# 2022-09-11: optimized internal flow: > alias > not found > admin down > peer state > ... +# 2023-01-21: changed to always yield fsm_established_time (not only if beep connects, but also on all other states) +# 2023-01-22: fix output for admin_state +# 2023-02-16: changed for CMK 2.1 (moved gui files from local/share/.. to local/lib/..) +# fix type error in discovery (CMK2.1 GUI only) +# 2023-02-20: fix crash if metric data is None +# 2023-03-26: optimized output of metrics, GetRateError will not be set to 0 anymore +# 2023-08-17: fix removed internal_item form check_default_parameters (THX mail[at]bastian-kuhn[dot]de) +# added warning if internal_item is missing in params +# 2024-06-07: fixed crash on configured state mapping +# 2024-12-20: added local address/as/identifier for bgp_topology +# 2025-03-29: refactored for ruleset APIv1 + +# Example Agent Output: +# BGP4-MIB + +# .1.3.6.1.2.1.15.3.1.1.192.168.254.2 = IpAddress: 192.168.254.2 +# .1.3.6.1.2.1.15.3.1.2.192.168.254.2 = INTEGER: 3 +# .1.3.6.1.2.1.15.3.1.3.192.168.254.2 = INTEGER: 2 +# .1.3.6.1.2.1.15.3.1.4.192.168.254.2 = INTEGER: 4 +# .1.3.6.1.2.1.15.3.1.5.192.168.254.2 = IpAddress: 0.0.0.0 +# .1.3.6.1.2.1.15.3.1.7.192.168.254.2 = IpAddress: 192.168.254.2 +# .1.3.6.1.2.1.15.3.1.9.192.168.254.2 = INTEGER: 65301 +# .1.3.6.1.2.1.15.3.1.10.192.168.254.2 = Counter32: 0 +# .1.3.6.1.2.1.15.3.1.11.192.168.254.2 = Counter32: 5 +# .1.3.6.1.2.1.15.3.1.14.192.168.254.2 = Hex-STRING: 04 00 +# .1.3.6.1.2.1.15.3.1.16.192.168.254.2 = Gauge32: 6586822 +# + +import time +from typing import Dict, List, Generator + +from cmk.agent_based.v2 import ( + CheckPlugin, + CheckResult, + DiscoveryResult, + GetRateError, + Metric, + Result, + SNMPSection, + SNMPTree, + Service, + State, + StringTable, + check_levels, + exists, + get_rate, + get_value_store, + render, +) + +from cmk_addons.plugins.bgp_peer.lib.bgp_peer import ( + BgpPeer, + bgp_adminstate, + bgp_get_peer_entry, + bgp_peerstate, +) + + +def parse_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer] | None: + peer_table = {} + try: + peer_info, local_info = string_table + except ValueError: + return None + + try: + local_as, local_id = local_info[0] + except (IndexError, ValueError): + local_as, local_id = None, None + + for entry in peer_info: + remote_addr, remote_id, peer_state, admin_state, local_addr, remote_as, in_updates, out_updates, \ + in_messages, out_messages, fsm_established_transitions, fsm_established_time, in_update_elapsed_time = entry + + bgp_peer = bgp_get_peer_entry( + admin_state=admin_state, + fsm_established_time=fsm_established_time, + fsm_established_transitions=fsm_established_transitions, + in_messages=in_messages, + in_update_elapsed_time=in_update_elapsed_time, + in_updates=in_updates, + local_addr=local_addr, + out_messages=out_messages, + out_updates=out_updates, + peer_state=peer_state, + remote_addr=remote_addr, + remote_as=remote_as, + remote_id=remote_id, + local_as=local_as, + local_id=local_id, + ) + if bgp_peer: + peer_table.update(bgp_peer) + return peer_table + + +def discovery_bgp_peer(params, section: Dict[str, BgpPeer]) -> DiscoveryResult: + _item_parts = [ + 'remote_address', + 'remote_as', + 'address_family', + 'routing_instance', + ] + for key in section.keys(): + parameters = {'internal_item': key} + item = '' + for item_part in _item_parts: + if item_part not in params['build_item']: + item += f'{section[key].item[item_part]} ' + item = item.strip(' ') + yield Service(item=item, parameters=parameters) + + +def bgp_peer_base_info(peer: BgpPeer) -> Generator: + for message, value in [ + ('Local AS:', peer.local_as), + ('Local address:', peer.local_addr), + ('Local identifier:', peer.local_id), + ('Remote AS:', peer.remote_as), + ('Remote address:', peer.remote_addr), + ('Remote identifier:', peer.remote_id), + ]: + if value is not None: + yield Result(state=State.OK, notice=f'{message} {value}') + + +def _rewrite_ruleset_needed(params: dict) -> bool: + for param, value in params.items(): + match param: + case 'accepted_prefixes_lower_levels' | 'accepted_prefixes_upper_levels' | 'minuptime': + if isinstance(value, tuple) and len(value) == 2 \ + and isinstance(value[0], int) and isinstance(value[1], int): + return True + case 'neighborstate': + for key in value.keys(): + if key in '123456': + return True + case 'peer_list': + if isinstance(value[0], tuple): + return True + return False + + +def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult: + if not params.get('internal_item'): + yield Result( + state=State.WARN, + summary='This service is using old parameters (see details)', + details='This service is using old parameters. To refresh the parameters you need to do a "Tabula rasa" ' + '(Discover services -> Remove all and find new)', + ) + else: + item = params['internal_item'] + + if _rewrite_ruleset_needed(params): + yield Result(state=State.WARN, + summary='BGP ruleset needs to be opened and saved to migrate the ruleset to ruleset APIv1!') + return + + neighbor_state = { + '1': 2, # idle + '2': 1, # connect + '3': 1, # active + '4': 1, # opensent + '5': 1, # openconfirm + '6': 0, # established + } + + neighbor_state.update(params['neighborstate']) + peer_not_found_state = params['peernotfound'] + + for entry in params.get('peer_list', []): + if item == entry['bgp_peer']: + if entry.get('bgp_peer_alias'): + yield Result(state=State.OK, summary=f'[{entry["bgp_peer_alias"]}]', details=' ') + peer_not_found_state = entry.get('state_not_found', params['peernotfound']) + + # get item data + try: + peer = section[item] + except KeyError: + yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data') + return + + if peer.description: + yield Result(state=State.OK, summary=f'[{peer.description}]', details=' ') + + if peer.admin_state == 1: # shutdown + yield Result(state=State(params['admindown']), summary=f'Admin state: {bgp_adminstate(peer.admin_state)}') + yield from bgp_peer_base_info(peer) + return + + yield Result( + state=State(neighbor_state.get(str(peer.peer_state))), + notice=f'Peer state: {bgp_peerstate(peer.peer_state)}' + ) + + if peer.fsm_established_time: # always yield fsm_established time + yield Metric( + name=f'bgp_peer_fsmestablishedtime', + value=peer.fsm_established_time, + boundaries=(0, None) + ) + + if not peer.peer_state == 6: # not established + yield from bgp_peer_base_info(peer) + return + + if peer.fsm_established_time: # if peer is established use fsm_established_time as uptime + yield from check_levels( + value=peer.fsm_established_time, + label='Uptime', + levels_upper=('no_levels', None), + levels_lower=params['minuptime'], + render_func=render.timespan, + metric_name='bgp_peer_fsmestablishedtime', + ) + + if peer.peer_unavail_reason != 0: # huawei peer unavailable state + yield Result(state=State.CRIT, notice=F'Peer unavailable reason: {peer.peer_unavail_reason_str}') + + if peer.device_admin_limit and peer.prefix_admin_limit is None: + yield Result( + state=State(params['noprefixlimit']), + notice='Prefix limit/warn threshold not configured on the device.', + ) + + if peer.accepted_prefixes is not None and peer.peer_state == 6: # peer established and prefixes accepted + if peer.prefix_admin_limit is None or peer.prefix_threshold is None: + levels_upper = None + else: + # use float (100.0) to get xx.xx in division + levels_upper = ( + 'fixed', (int(peer.prefix_admin_limit / 100.0 * peer.prefix_threshold), peer.prefix_admin_limit) + ) + + yield from check_levels( + value=peer.accepted_prefixes, + metric_name='bgp_peer_acceptedprefixes', + levels_upper=params.get('accepted_prefixes_upper_levels', levels_upper), + levels_lower=params.get('accepted_prefixes_lower_levels'), + label='Prefixes accepted', + render_func=lambda v: f'{v}' + ) + + now_time = time.time() + value_store = get_value_store() + + for key, value in peer.metric_rate: + try: + value = get_rate(value_store, f'{key}', now_time, value, raise_overflow=True) + except GetRateError: + continue + yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None)) + + for key, value in peer.metric_count: + if value is not None: + yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None)) + + yield from bgp_peer_base_info(peer) + + +snmp_section_bgp_peer = SNMPSection( + name='bgp_peer', + parse_function=parse_bgp_peer, + fetch=[ + SNMPTree( + base='.1.3.6.1.2.1.15.3.1', # BGP4-MIB::BgpPeerEntry + oids=[ + '7', # bgpPeerRemoteAddr + '1', # bgpPeerIdentifier + '2', # bgpPeerState + '3', # bgpPeerAdminStatus + '5', # bgpPeerLocalAddr + '9', # bgpPeerRemoteAs + '10', # bgpPeerInUpdates + '11', # bgpPeerOutUpdates + '12', # bgpPeerInTotalMessages + '13', # bgpPeerOutTotalMessages + '15', # bgpPeerFsmEstablishedTransitions + '16', # bgpPeerFsmEstablishedTime + '24', # bgpPeerInUpdateElapsedTime + ]), + SNMPTree( + base='.1.3.6.1.2.1.15', # BGP4-MIB + oids=[ + '2', # bgpLocalAs + '4', # bgpIdentifier (local) + ]) + ], + detect=exists('.1.3.6.1.2.1.15.3.1.1.*') +) + +check_plugin_bgp_peer = CheckPlugin( + name='bgp_peer', + service_name='BGP peer %s', + discovery_function=discovery_bgp_peer, + discovery_default_parameters={ + 'build_item': [ + # 'remote_address', + 'remote_as', + # 'address_family', + # 'routing_instance', + ] + }, + discovery_ruleset_name='discovery_bgp_peer', + check_function=check_bgp_peer, + check_default_parameters={ + 'minuptime': ('fixed', (7200, 3600)), + 'peer_list': [], + 'peernotfound': 2, + 'admindown': 1, + 'noprefixlimit': 1, + 'neighborstate': { + 'idle': 2, # ........1 + 'connect': 1, # .....2 + 'active': 1, # ......3 + 'open_sent': 1, # ...4 + 'open_confirm': 1, # 5 + 'established': 0, # .6 + }, + }, + check_ruleset_name='bgp_peer', +) diff --git a/source/agent_based/inv_bgp_peer.py b/source/cmk_addons_plugins/bgp_peer/agent_based/inv_bgp_peer.py similarity index 94% rename from source/agent_based/inv_bgp_peer.py rename to source/cmk_addons_plugins/bgp_peer/agent_based/inv_bgp_peer.py index 869b3375b22d292caa3bd1e0cb1d7ab0280c3088..ce96d0771be2f288afc86212edf6518593ec3258 100644 --- a/source/agent_based/inv_bgp_peer.py +++ b/source/cmk_addons_plugins/bgp_peer/agent_based/inv_bgp_peer.py @@ -18,18 +18,18 @@ import time from typing import List -from cmk.base.plugins.agent_based.agent_based_api.v1 import ( +from cmk.agent_based.v2 import ( + InventoryPlugin, + InventoryResult, OIDBytes, + SNMPSection, SNMPTree, + StringByteTable, TableRow, exists, - register, -) -from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( - InventoryResult, - StringByteTable, ) -from cmk.base.plugins.agent_based.utils.bgp_peer import ( + +from cmk_addons.plugins.bgp_peer.lib.bgp_peer import ( BgpWhois, InvBgpPeer, bgp_error_as_string, @@ -132,7 +132,7 @@ def inventory_bgp_peers(params, section) -> InventoryResult: del whois -register.snmp_section( +snmp_section_inv_bgp_peer = SNMPSection( name='inv_bgp_peer', parse_function=parse_inv_bgp_peer, fetch=[ @@ -160,7 +160,7 @@ register.snmp_section( detect=exists('.1.3.6.1.2.1.15.3.1.1.*') ) -register.inventory_plugin( +inventory_plugin_inv_bgp_peer = InventoryPlugin( name='inv_bgp_peer', inventory_function=inventory_bgp_peers, inventory_default_parameters={ diff --git a/source/checkman/bgp_peer b/source/cmk_addons_plugins/bgp_peer/checkman/bgp_peer similarity index 100% rename from source/checkman/bgp_peer rename to source/cmk_addons_plugins/bgp_peer/checkman/bgp_peer diff --git a/source/cmk_addons_plugins/bgp_peer/graphing/bgp_peer.py b/source/cmk_addons_plugins/bgp_peer/graphing/bgp_peer.py new file mode 100644 index 0000000000000000000000000000000000000000..b40ffd9f23bacf6e6168aa8b6676a5ddf6dda332 --- /dev/null +++ b/source/cmk_addons_plugins/bgp_peer/graphing/bgp_peer.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2021-08-21 +# +# BGP Peer metrics plugin +# +# 2024-05-17: fixed typo in range mac -> max (crashed graphs in cmk 2.3.) +# 2025-03-29: rewritten for graphing API v1 + +from cmk.graphing.v1 import Title, graphs, metrics, perfometers + + +UNIT_COUNTER = metrics.Unit(metrics.DecimalNotation(''), metrics.StrictPrecision(2)) +UNIT_PER_SECOND = metrics.Unit(metrics.DecimalNotation('/s')) +UNIT_TIME = metrics.Unit(metrics.TimeNotation()) + +metric_bgp_peer_accepted_prefixes = metrics.Metric( + name='bgp_peer_acceptedprefixes', + title=Title("Prefixes accepted"), + unit=UNIT_COUNTER, + color=metrics.Color.DARK_PURPLE, +) + +metric_bgp_peer_advertised_prefixes = metrics.Metric( + name='bgp_peer_advertisedprefixes', + title=Title("Prefixes advertised"), + unit=UNIT_PER_SECOND, + color=metrics.Color.CYAN, +) + +metric_bgp_peer_denied_prefixes = metrics.Metric( + name='bgp_peer_deniedprefixes', + title=Title("Prefixes denied"), + unit=UNIT_PER_SECOND, + color=metrics.Color.YELLOW, +) + +metric_bgp_peer_fsm_established_time = metrics.Metric( + name='bgp_peer_fsmestablishedtime', + title=Title("FSM last change"), + unit=UNIT_TIME, + color=metrics.Color.GREEN, +) + +metric_bgp_peer_fsm_established_transitions = metrics.Metric( + name='bgp_peer_fsmestablishedtransitions', + title=Title("FSM transitions"), + unit=UNIT_COUNTER, + color=metrics.Color.YELLOW, +) + +metric_bgp_peer_in_total_messages = metrics.Metric( + name='bgp_peer_intotalmessages', + title=Title("Messages received"), + unit=UNIT_PER_SECOND, + color=metrics.Color.DARK_BLUE, +) + +metric_bgp_peer_in_update_elapsed_time = metrics.Metric( + name='bgp_peer_inupdateelapsedtime', + title=Title("Last update received"), + unit=UNIT_TIME, + color=metrics.Color.DARK_BLUE, +) + +metric_bgp_peer_in_updates = metrics.Metric( + name='bgp_peer_inupdates', + title=Title("Updates received"), + unit=UNIT_PER_SECOND, + color=metrics.Color.YELLOW, +) + +metric_bgp_peer_out_total_messages = metrics.Metric( + name='bgp_peer_outtotalmessages', + title=Title("Messages send"), + unit=UNIT_PER_SECOND, + color=metrics.Color.DARK_PINK, +) + +metric_bgp_peer_out_updates = metrics.Metric( + name='bgp_peer_outupdates', + title=Title("Updates send"), + unit=UNIT_PER_SECOND, + color=metrics.Color.CYAN, +) + +metric_bgp_peer_suppressed_prefixes = metrics.Metric( + name='bgp_peer_suppressedprefixes', + title=Title("Prefixes suppressed"), + unit=UNIT_PER_SECOND, + color=metrics.Color.DARK_PINK, +) + +metric_bgp_peer_withdrawn_prefixes = metrics.Metric( + name='bgp_peer_withdrawnprefixes', + title=Title("Prefixes withdrawn"), + unit=UNIT_PER_SECOND, + color=metrics.Color.BLUE, +) + +# Juniper specific metrics +metric_bgp_peer_in_prefixes = metrics.Metric( + name='bgp_peer_in_prefixes', + title=Title("Prefixes in"), + unit=UNIT_COUNTER, + color=metrics.Color.DARK_PURPLE, +) + +metric_bgp_peer_in_prefixes_rejected = metrics.Metric( + name='bgp_peer_in_prefixes_rejected', + title=Title("Prefixes in rejected"), + unit=UNIT_COUNTER, + color=metrics.Color.YELLOW, +) + +metric_bgp_peer_in_prefixes_active = metrics.Metric( + name='bgp_peer_in_prefixes_active', + title=Title("Prefixes in active"), + unit=UNIT_COUNTER, + color=metrics.Color.CYAN, +) + +metric_bgp_peer_out_prefixes = metrics.Metric( + name='bgp_peer_out_prefixes', + title=Title("Prefixes out"), + unit=UNIT_COUNTER, + color=metrics.Color.BLUE, +) + +# Huawei specific metrics +metric_bgp_peer_prefix_adv_counter = metrics.Metric( + name='bgp_peer_prefixadvcounter', + title=Title("Prefixes advertised"), + unit=UNIT_COUNTER, + color=metrics.Color.DARK_BLUE, +) + +metric_bgp_peer_prefix_active_counter = metrics.Metric( + name='bgp_peer_prefixactivecounter', + title=Title("Prefixes active"), + unit=UNIT_COUNTER, + color=metrics.Color.CYAN, +) + +metric_bgp_peer_prefix_rcv_counter = metrics.Metric( + name='bgp_peer_prefixrcvcounter', + title=Title("Prefixes received"), + unit=UNIT_COUNTER, + color=metrics.Color.DARK_PURPLE, +) + +graph_bgp_peer_fms_transitions_last_change = graphs.Graph( + name='bgp_peer.fms_transitions_last_change', + title=Title("FSM established last change"), + minimal_range=graphs.MinimalRange(0, metrics.MaximumOf('bgp_peer_fsmestablishedtime', metrics.Color.GRAY, ), ), + compound_lines=['bgp_peer_fsmestablishedtime'], +) + +graph_bgp_peer_prefixes_accepted = graphs.Graph( + name='bgp_peer.prefixes_accepted', + title=Title("Accepted Prefixes"), + minimal_range=graphs.MinimalRange(0, metrics.MaximumOf('bgp_peer_acceptedprefixes', metrics.Color.GRAY, ), ), + compound_lines=['bgp_peer_acceptedprefixes'], + simple_lines=[ + metrics.CriticalOf('bgp_peer_acceptedprefixes'), + metrics.WarningOf('bgp_peer_acceptedprefixes'), + ], +) + +graph_bgp_peer_prefixes_per_second = graphs.Graph( + name='bgp_peer.prefixes_per_second', + title=Title("Prefixes/s"), + simple_lines=[ + 'bgp_peer_withdrawnprefixes', + 'bgp_peer_suppressedprefixes', + 'bgp_peer_deniedprefixes', + 'bgp_peer_advertisedprefixes', + ], + optional=[ + 'bgp_peer_withdrawnprefixes', + 'bgp_peer_suppressedprefixes', + 'bgp_peer_deniedprefixes', + 'bgp_peer_advertisedprefixes', + ], +) + +graph_bgp_peer_updates_in_out = graphs.Bidirectional( + name='bgp_peer.updates_in_out', + title=Title("Updates"), + lower=graphs.Graph( + name='bgp_peer.updates_in_out_lower', + title=Title("Updates"), + compound_lines=['bgp_peer_outupdates'], + ), + upper=graphs.Graph( + name='bgp_peer.updates_in_out_upper', + title=Title("Updates"), + compound_lines=['bgp_peer_inupdates'], + ), +) + +graph_bgp_peer_messages_in_out = graphs.Bidirectional( + name='bgp_peer.messages_in_out', + title=Title("Total messages"), + lower=graphs.Graph( + name='bgp_peer.messages_in_out_lower', + title=Title("Total messages"), + compound_lines=['bgp_peer_outtotalmessages'], + ), + upper=graphs.Graph( + name='bgp_peer.messages_in_out_upper', + title=Title("Total messages"), + compound_lines=['bgp_peer_intotalmessages'], + ), +) + +graph_bgp_peer_fms_transitions_from_to = graphs.Graph( + name='bgp_peer.fms_transitions_from_to', + title=Title("FSM transitions from/to established"), + minimal_range=graphs.MinimalRange( + 0, metrics.MaximumOf('bgp_peer_fsmestablishedtransitions', metrics.Color.GRAY, ), + ), + compound_lines=['bgp_peer_fsmestablishedtransitions'], +) + +graph_bgp_peer_time_since_last_update = graphs.Graph( + name='bgp_peer.time_since_last_update', + title=Title("Time since last update received"), + minimal_range=graphs.MinimalRange( + 0, metrics.MaximumOf('bgp_peer_inupdateelapsedtime', metrics.Color.GRAY, ), + ), + compound_lines=['bgp_peer_inupdateelapsedtime'], +) + +# juniper prefixes +graph_bgp_peer_juniper_prefixes = graphs.Bidirectional( + name='bgp_peer.juniper_prefixes', + title=Title("Prefixes in/out"), + lower=graphs.Graph( + name='bgp_peer.juniper_prefixes_lower', + title=Title("Prefixes in/out"), + simple_lines=['bgp_peer_out_prefixes'], + ), + upper=graphs.Graph( + name='bgp_peer.juniper_prefixes_upper', + title=Title("Prefixes in/out"), + simple_lines=[ + 'bgp_peer_in_prefixes_rejected', + 'bgp_peer_in_prefixes_active', + 'bgp_peer_in_prefixes', + ], + ), +) + +# huawei prefixes +graph_huawei_bgp_peer_counter = graphs.Graph( + name='huawei_bgp_peer_counter', + title=Title("BGP prefix counter"), + simple_lines=[ + 'bgp_peer_prefixrcvcounter', + 'bgp_peer_prefixactivecounter', + 'bgp_peer_prefixadvcounter', + ], +) + + +perfometer_bgp_peer_accepted_prefixes = perfometers.Stacked( + name='bgp_peer_stacked', + upper=perfometers.Perfometer( + name='bgp_peer_fsmestablishedtime', + segments=['bgp_peer_fsmestablishedtime'], + focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(2592000)) # ome month + ), + lower=perfometers.Perfometer( + name='bgp_peer_acceptedprefixes', + segments=['bgp_peer_acceptedprefixes'], + focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(500000)) + ) +) + +perfometer_bgp_peer_fsm_established_time = perfometers.Perfometer( + name='bgp_peer_fsmestablishedtime', + segments=['bgp_peer_fsmestablishedtime'], + focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(2592000)) # ome month +) \ No newline at end of file diff --git a/source/agent_based/utils/bgp_peer.py b/source/cmk_addons_plugins/bgp_peer/lib/bgp_peer.py similarity index 100% rename from source/agent_based/utils/bgp_peer.py rename to source/cmk_addons_plugins/bgp_peer/lib/bgp_peer.py diff --git a/source/cmk_addons_plugins/bgp_peer/rulesets/bgp_peer.py b/source/cmk_addons_plugins/bgp_peer/rulesets/bgp_peer.py new file mode 100644 index 0000000000000000000000000000000000000000..fe1df4b39dfb2b44baa5f35f628109b980d61ee1 --- /dev/null +++ b/source/cmk_addons_plugins/bgp_peer/rulesets/bgp_peer.py @@ -0,0 +1,336 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2017-12-25 +# +# Check_MK bgp_peers WATO plugin +# +# 2021-03-27: rewrite for CMK 2.0 +# 2021-08-21: modified for bgp_peer plugin (from cisco_bgp_peer) +# 2021-08-29: removed htmloutput and infotext_values option +# 2022-04-02: added bgp neighbour states +# 2022-04-29: added upper/lower prefix limit +# 2022-05-09: added discovery rule set +# 2022-05-11: added remote_as to build_item +# 2022-09-05: added internal_item to avoid warnings on cmk updates (THX to Jay2k1 for reporting the issue) +# 2023-06-11: moved wato file from ~local/lib/check_mk/gui/plugins/wato +# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters to override the build in wato plugin +# 2024-06-15: fixed typo (no not) +# +# Known issue: the override of the build in wato plugin will break the build in aritsa bgp peer plugin +from click import help_option +from cmk.rulesets.v1 import Help, Label, Title +from cmk.rulesets.v1.form_specs import ( + DefaultValue, + DictElement, + Dictionary, + InputHint, + Integer, + LevelDirection, + LevelsType, + List, + MultipleChoice, + MultipleChoiceElement, + ServiceState, + SimpleLevels, + String, + TimeMagnitude, + TimeSpan, + migrate_to_integer_simple_levels, +) +from cmk.rulesets.v1.rule_specs import CheckParameters, DiscoveryParameters, Topic, HostAndItemCondition +from cmk.rulesets.v1.form_specs.validators import NumberInRange, Message, LengthInRange + +item_parts = [ + # MultipleChoiceElement(name='remote_address', title=Title('Peer remote address')), + MultipleChoiceElement(name='remote_as', title=Title('Remote AS')), + MultipleChoiceElement(name='address_family', title=Title('Address family')), + MultipleChoiceElement(name='routing_instance', title=Title('Routing instance/VRF')), +] + +def _migrate_to_float(value: object) -> float: + if isinstance(value, int | float): + return float(value) + + raise TypeError(value) + +def _migrate_bgp_peer_list(value: object) -> list: + if not isinstance(value, list): + raise TypeError(value) + + peer_list = [] + + for entry in value: + if isinstance(entry, tuple): + bgp_peer, bgp_peer_alias, state_not_found = entry + peer_list.append({ + 'bgp_peer': bgp_peer, + 'bgp_peer_alias': bgp_peer_alias, + 'state_not_found': state_not_found + }) + else: + peer_list.append(entry) + + return peer_list + + +def _migrate_neighbor_state(value: object) -> dict: + if not isinstance(value, dict): + raise TypeError(value) + + state_map = {} + + for state, value in value.items(): + match state: + case '1': + state_map['idle'] = value + case '2': + state_map['connect'] = value + case '3': + state_map['active'] = value + case '4': + state_map['open_sent'] = value + case '5': + state_map['open_confirm'] = value + case '6': + state_map['established'] = value + case _: + state_map[state] = value + + return state_map + +def _parameter_form_check_bgp_peer(): + return Dictionary( + elements={ + 'minuptime': DictElement( + parameter_form=SimpleLevels( + title=Title('Minimum uptime for peer'), + help_text=Help('Set the time in seconds, a peer must be up before the peer is considered sable.'), + prefill_levels_type=DefaultValue(LevelsType.FIXED), + prefill_fixed_levels=InputHint((7200, 3600)), + level_direction=LevelDirection.LOWER, + migrate=migrate_to_integer_simple_levels, + form_spec_template=TimeSpan( + displayed_magnitudes=[TimeMagnitude.SECOND, TimeMagnitude.MINUTE, TimeMagnitude.HOUR], + custom_validate=(NumberInRange(min_value=0),), + migrate=_migrate_to_float, + ))), + 'accepted_prefixes_upper_levels': DictElement( + parameter_form=SimpleLevels( + title=Title('Accepted prefixes upper levels'), + help_text=Help('The values from WATO are preferred to the values from the device.'), + prefill_levels_type=DefaultValue(LevelsType.FIXED), + prefill_fixed_levels=InputHint((0, 0)), + level_direction=LevelDirection.UPPER, + migrate=migrate_to_integer_simple_levels, + form_spec_template=Integer( + unit_symbol='prefixes', + custom_validate=(NumberInRange(min_value=0, ),) + ))), + 'accepted_prefixes_lower_levels': DictElement( + parameter_form=SimpleLevels( + title=Title('Accepted prefixes lower levels'), + help_text=Help('The values from WATO are preferred to the values from the device.'), + prefill_levels_type=DefaultValue(LevelsType.FIXED), + prefill_fixed_levels=InputHint((0, 0)), + level_direction=LevelDirection.LOWER, + migrate=migrate_to_integer_simple_levels, + form_spec_template=Integer( + unit_symbol='prefixes', + custom_validate=(NumberInRange(min_value=0, ),), + ))), + 'peernotfound': DictElement( + parameter_form=ServiceState( + title=Title('State if peer is not found.'), + help_text=Help('Default monitoring state if the peer is not found in the SNMP data'), + prefill=DefaultValue(2) + )), + 'admindown': DictElement( + parameter_form=ServiceState( + prefill=DefaultValue(1), + title=Title('State if peer is admin shutdown.'), + help_text=Help('Monitoring state if the peer is admin shutdown') + )), + + 'neighborstate': DictElement( + parameter_form=Dictionary( + title=Title('State to report for BGP neighbor state'), + help_text=Help('Map each BGP state to a CheckMK monitoring state'), + migrate=_migrate_neighbor_state, + elements={ + 'idle': DictElement( + parameter_form=ServiceState( + title=Title('1 - idle'), + help_text=Help( + 'This is the first stage of the BGP FSM. BGP detects a start event, tries to initiate a ' + 'TCP connection to the BGP peer, and also listens for a new connect from a peer router. ' + 'If an error causes BGP to go back to the Idle state for a second time, the ' + 'ConnectRetryTimer is set to 60 seconds and must decrement to zero before the connection ' + 'is initiated again. Further failures to leave the Idle state result in the ' + 'ConnectRetryTimer doubling in length from the previous time. ' + 'Default monitoring state is "CRIT"' + ), + prefill=DefaultValue(2) + )), + 'connect': DictElement( + parameter_form=ServiceState( + title=Title('2 - connect'), + help_text=Help( + 'In this state, BGP initiates the TCP connection. If the 3-way TCP handshake completes, ' + 'the established BGP Session BGP process resets the ConnectRetryTimer and sends the Open ' + 'message to the neighbor, and then changes to the OpenSent State.' + 'Default monitoring state is "WARN"'), + prefill=DefaultValue(1), + )), + 'active': DictElement( + parameter_form=ServiceState( + title=Title('3 - active'), + help_text=Help( + 'In this state, BGP starts a new 3-way TCP handshake. If a connection is established, ' + 'an Open message is sent, the Hold Timer is set to 4 minutes, and the state moves to ' + 'OpenSent. If this attempt for TCP connection fails, the state moves back to the Connect ' + 'state and resets the ConnectRetryTimer. ' + 'Default monitoring state is "WARN"'), + prefill=DefaultValue(1), + )), + 'open_sent': DictElement( + parameter_form=ServiceState( + title=Title('4 - opensent'), + help_text=Help( + 'In this state, an Open message has been sent from the originating router and is awaiting ' + 'an Open message from the other router. After the originating router receives the OPEN ' + 'message from the other router, both OPEN messages are checked for errors. If the Open ' + 'messages do not have any errors, the Hold Time is negotiated (using the lower value), ' + 'and a KEEPALIVE message is sent (assuming the value is not set to zero). The connection ' + 'state is then moved to OpenConfirm. If an error is found in the OPEN message, a ' + 'Notification message is sent, and the state is moved back to Idle.' + ' Default monitoring state is "WARN"'), + prefill=DefaultValue(1), + )), + 'open_confirm': DictElement( + parameter_form=ServiceState( + title=Title('5 - openconfirm'), + help_text=Help( + 'In this state, BGP waits for a Keepalive or Notification message. Upon receipt of a ' + 'neighbor’s Keepalive, the state is moved to Established. If the hold timer expires, a ' + 'stop event occurs, or a Notification message is received, and the state is moved to ' + 'Idle. ' + 'Default monitoring state is "WARN"'), + prefill=DefaultValue(1), + )), + 'established': DictElement( + parameter_form=ServiceState( + title=Title('6 - established'), + help_text=Help( + 'In this state, the BGP session is established. BGP neighbors exchange routes via Update ' + 'messages. As Update and Keepalive messages are received, the Hold Timer is reset. If the ' + 'Hold Timer expires, an error is detected and BGP moves the neighbor back to the Idle ' + 'state. ' + 'Default monitoring state is "OK"'), + prefill=DefaultValue(0), + )), + } + )), + + 'noprefixlimit': DictElement( + parameter_form=ServiceState( + title=Title('State if no admin prefix limit/warn threshold is configured.'), + help_text=Help( + 'The admin prefix limit and warn threshold needs to be configured on the device. ' + 'For example: "neighbor 172.17.10.10 maximum-prefix 10000 80". The threshold is in percentage ' + 'of the prefix limit.' + ), + prefill=DefaultValue(1), + )), + 'peer_list': DictElement( + parameter_form=List( + title=Title('BGP Peers'), + add_element_label=Label('Add BGP peer'), + remove_element_label=Label('remove BGP peer'), + no_element_label=Label('Add at least one BGP peer'), + migrate=_migrate_bgp_peer_list, + element_template=Dictionary( + elements={ + 'bgp_peer': DictElement( + required=True, + parameter_form=String( + title=Title('BGP peer'), + help_text=Help( + 'The configured value must match a BGP item reported by the monitored ' + 'device. For example: "10.194.115.98" or "2A10:1CD0:1020:135::20 IPv6 Unicast"' + ), + custom_validate=(LengthInRange(min_value=1, ),), + )), + 'bgp_peer_alias': DictElement( + parameter_form=String( + title=Title('BGP Peer Alias'), + help_text=Help( + 'You can configure an individual alias here for the BGP peer matching ' + 'the text configured in the "BGP Peer IP-address" field. The alias will ' + 'be shown in the check info' + ), + custom_validate=(LengthInRange(min_value=1, ),), + )), + 'state_not_found': DictElement( + required=True, + parameter_form=ServiceState( + title=Title('State if not found'), + help_text=Help( + 'You can configure an individual state if the BGP peer matching the text ' + 'configured in the "BGP Peer IP-address" field is not found' + ), + prefill=DefaultValue(2), + )), + } + ) + )), + 'internal_item': DictElement( + render_only=True, + parameter_form=MultipleChoice( + title=Title('Information not to use in the item name'), + elements=item_parts, + )), + } + ) + + +rule_spec_check_bgp_peer = CheckParameters( + name='bgp_peer', + parameter_form=_parameter_form_check_bgp_peer, + title=Title('BGP Peer'), + topic=Topic.NETWORKING, + condition=HostAndItemCondition(item_title=Title('BGP peer')), +) + + +def _parameter_form_discovery_bgp_peer(): + return Dictionary( + elements={ + 'build_item': DictElement( + parameter_form=MultipleChoice( + title=Title('Information not to use in the item name'), + help_text=Help( + 'The Peer remote address is always used as the item name. By default the check will add the ' + 'address-family and the routing instance/VRF if available. You can decide to not use these ' + 'additional information in the item name. Do so only if your peers have only one address-' + 'family configured and you don\'t have the same peer remote address in different routing ' + 'instances/VRFs configured.' + ), + elements=item_parts, + prefill=DefaultValue(['remote_as']) + ) + ) + } + ) + + +rule_spec_discovery_bgp_beer = DiscoveryParameters( + title=Title('BGP peer'), + topic=Topic.NETWORKING, + name='discovery_bgp_peer', + parameter_form=_parameter_form_discovery_bgp_peer, +) diff --git a/source/cmk_addons_plugins/bgp_peer/rulesets/inv_bgp_peer.py b/source/cmk_addons_plugins/bgp_peer/rulesets/inv_bgp_peer.py new file mode 100644 index 0000000000000000000000000000000000000000..f1d30bc35f50ae358697a25a6c573be9579bd207 --- /dev/null +++ b/source/cmk_addons_plugins/bgp_peer/rulesets/inv_bgp_peer.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2022-04-24 +# +# 2022-04-24: added option for BGP down time +# added option to remove some columns from inventory +# 2022-04-28: added Whois options +# 2023-06-12: moved wato file from ~local/lib/check_mk/gui/plugins/wato +# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters +# 2025-03-29: rewritten for rulesets API v1 + +from cmk.rulesets.v1 import Title, Help +from cmk.rulesets.v1.form_specs import ( + DefaultValue, + DictElement, + Dictionary, + Integer, + MultipleChoice, + MultipleChoiceElement, + SingleChoice, + SingleChoiceElement, + TimeMagnitude, + TimeSpan, +) +from cmk.rulesets.v1.rule_specs import InventoryParameters, Topic +from cmk.rulesets.v1.form_specs.validators import NumberInRange, Message + +def _migrate_to_float(value: object) -> float: + if isinstance(value, int | float): + return float(value) + + raise TypeError(value) + + +def _parameter_form_inv_bgp_peer(): + remove_columns = [ + # MultipleChoiceElement(name='remote_as', title=Title('Remote AS')), + # MultipleChoiceElement(name='remote_id', title=Title('Remote ID')), + # MultipleChoiceElement(name='local_addr', title=Title('Local address')), + # MultipleChoiceElement(name='local_as', title=Title('Local AS')), + # MultipleChoiceElement(name='local_id', title=Title('Local ID')), + # MultipleChoiceElement(name='prev_state', title=Title('Previous state')), + MultipleChoiceElement(name='address_family', title=Title('Address family')), + MultipleChoiceElement(name='last_error', title=Title('Last error')), + MultipleChoiceElement(name='last_error_code', title=Title('Last error code')), + MultipleChoiceElement(name='as_name', title=Title('Remote AS name')), + MultipleChoiceElement(name='as_org_name', title=Title('Remote AS Org Name')), + MultipleChoiceElement(name='bgp_type', title=Title('Type')), + MultipleChoiceElement(name='version', title=Title('Version')), + ] + + rir_s = [ + SingleChoiceElement(name='afrinic', title=Title('AFRINIC (https://rdap.afrinic.net/rdap)')), + SingleChoiceElement(name='apnic', title=Title('APNIC (https://rdap.apnic.net)')), + SingleChoiceElement(name='arin', title=Title('ARIN (https://rdap.arin.net/registry)')), + SingleChoiceElement(name='ripe', title=Title('RIPE (https://rdap.db.ripe.net)')), + SingleChoiceElement(name='lacnic', title=Title('LACNIC (https://rdap.apnic.net)')), + ] + + return Dictionary( + elements={ + 'not_in_service_time': DictElement( + parameter_form=TimeSpan( + title=Title('Time peer is not up until considered not in service'), + displayed_magnitudes=[TimeMagnitude.MINUTE, TimeMagnitude.HOUR, TimeMagnitude.DAY], + prefill=DefaultValue(2592000.0), # 30 days in seconds + migrate=_migrate_to_float, + )), + 'remove_columns': DictElement( + parameter_form=MultipleChoice( + title=Title('List of columns to remove'), + help_text=Help('Information to remove from inventory'), + elements=remove_columns, + )), + 'whois_enable': DictElement( + parameter_form=Dictionary( + title=Title('Add whois data to the inventory'), + help_text=Help( + 'The whois data will be fetched via RDAP from the registries. For this the the plugin tries to' + 'find the best registry via the RDAP bootstrap data from https://data.iana.org/rdap/asn.json.' + 'The query it self will go to the found registry via http(s). Note: the request might be get ' + 'redirected if there a different authoritative registry for the ASn' + ), + elements={ + 'whois_rir': DictElement( + parameter_form=SingleChoice( + title=Title('Preferred RIR to fetch whois data'), + help_text=Help( + 'This registry will be used if the plugin can not determine the authoritative registry ' + 'based on the bootstrap data.' + ), + elements=rir_s, + prefill=DefaultValue('ripe'), + )), + 'whois_timeout': DictElement( + parameter_form=Integer( + custom_validate=( + NumberInRange( + min_value=1, + max_value=None, + error_msg=Message('The timeout must be greater than 0') + ), + ), + help_text=Help('The connection timeout for each whois request.'), + prefill=DefaultValue(5), + title=Title('Timeout for connections to RIRs'), + unit_symbol='seconds', + )), + } + ) + ) + } + ) + + +rule_spec_inv_bgp_peer = InventoryParameters( + name='inv_bgp_peer', + parameter_form=_parameter_form_inv_bgp_peer, + title=Title('BGP peer'), + topic=Topic.NETWORKING, +) diff --git a/source/gui/metrics/bgp_peer.py b/source/gui/metrics/bgp_peer.py deleted file mode 100644 index a6f8bcfef666f906a9c6f46baaf268ff56e8ac59..0000000000000000000000000000000000000000 --- a/source/gui/metrics/bgp_peer.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# License: GNU General Public License v2 -# -# Author: thl-cmk[at]outlook[dot]com -# URL : https://thl-cmk.hopto.org -# Date : 2021-08-21 -# -# BGP Peer metrics plugin -# -# 2024-05-17: fixed typo in range mac -> max (crashed graphs in cmk 2.3.) -# -from cmk.gui.i18n import _ - -from cmk.gui.plugins.metrics.utils import ( - metric_info, - graph_info, - perfometer_info -) - -##################################################################################################################### -# -# define metrics for bgp peer perfdata -# -##################################################################################################################### - -metric_info['bgp_peer_inupdates'] = { - 'title': _('Updates received'), - 'unit': '1/s', - 'color': '22/a', -} -metric_info['bgp_peer_outupdates'] = { - 'title': _('Updates send'), - 'unit': '1/s', - 'color': '32/a', -} -metric_info['bgp_peer_intotalmessages'] = { - 'title': _('Messages received'), - 'unit': '1/s', - 'color': '42/a', -} -metric_info['bgp_peer_outtotalmessages'] = { - 'title': _('Messages send'), - 'unit': '1/s', - 'color': '13/a', -} -metric_info['bgp_peer_fsmestablishedtransitions'] = { - 'title': _('FSM transitions'), - 'unit': 'count', - 'color': '23/a', -} -metric_info['bgp_peer_fsmestablishedtime'] = { - 'title': _('FSM last change'), - 'unit': 's', - 'color': '26/a', -} -metric_info['bgp_peer_inupdateelapsedtime'] = { - 'title': _('Last update received'), - 'unit': 's', - 'color': '43/a', -} - -metric_info['bgp_peer_acceptedprefixes'] = { - 'title': _('Prefixes accepted'), - 'help': _('number of accepted prefixes'), - 'unit': 'count', - 'color': '11/a', -} -metric_info['bgp_peer_deniedprefixes'] = { - 'title': _('Prefixes denied'), - 'unit': '1/s', - 'color': '21/a', -} -metric_info['bgp_peer_advertisedprefixes'] = { - 'title': _('Prefixes advertised'), - 'unit': '1/s', - 'color': '31/a', -} -metric_info['bgp_peer_withdrawnprefixes'] = { - 'title': _('Prefixes withdrawn'), - 'unit': '1/s', - 'color': '41/a', -} -metric_info['bgp_peer_suppressedprefixes'] = { - 'title': _('Prefixes suppressed'), - 'unit': '1/s', - 'color': '12/a', -} - -# Juniper specific metrics -metric_info['bgp_peer_in_prefixes'] = { - 'title': _('Prefixes in'), - 'unit': 'count', - 'color': '11/a', -} -metric_info['bgp_peer_in_prefixes_rejected'] = { - 'title': _('Prefixes in rejected'), - 'unit': 'count', - 'color': '21/a', -} -metric_info['bgp_peer_in_prefixes_active'] = { - 'title': _('Prefixes in active'), - 'unit': 'count', - 'color': '31/a', -} -metric_info['bgp_peer_out_prefixes'] = { - 'title': _('Prefixes out'), - 'unit': 'count', - 'color': '41/a', -} - -# Hawei spezific metrics -metric_info['bgp_peer_prefixrcvcounter'] = { - 'title': _('Prefixes received'), - 'unit': 'count', - 'color': '11/a', -} -metric_info['bgp_peer_prefixactivecounter'] = { - 'title': _('Prefixes active'), - 'unit': 'count', - 'color': '33/a', -} -metric_info['bgp_peer_prefixadvcounter'] = { - 'title': _('Prefixes advertised'), - 'unit': 'count', - 'color': '43/a', -} - -###################################################################################################################### -# -# how to graph perdata for bgp peer -# -###################################################################################################################### - -graph_info['bgp_peer.fms_transitions_last_change'] = { - 'title': _('FSM established last change'), - 'metrics': [ - ('bgp_peer_fsmestablishedtime', 'area'), - ], - 'range': (0, 'bgp_peer_fsmestablishedtime:max'), -} - -graph_info['bgp_peer.prefixes_accepted'] = { - 'title': _('Accepted Prefixes'), - 'metrics': [ - ('bgp_peer_acceptedprefixes', 'area'), - ], - 'scalars': [ - ('bgp_peer_acceptedprefixes:crit', _('crit')), - ('bgp_peer_acceptedprefixes:warn', _('warn')), - ], - 'range': (0, 'bgp_peer_acceptedprefixes:max'), -} - -graph_info['bgp_peer.prefixes_per_second'] = { - 'title': _('Prefixes/s'), - 'metrics': [ - ('bgp_peer_withdrawnprefixes', 'line'), - ('bgp_peer_suppressedprefixes', 'line'), - ('bgp_peer_deniedprefixes', 'line'), - ('bgp_peer_advertisedprefixes', 'line'), - ], - 'optional_metrics': [ - 'bgp_peer_withdrawnprefixes', - 'bgp_peer_suppressedprefixes', - 'bgp_peer_deniedprefixes', - 'bgp_peer_advertisedprefixes', - ], -} - -graph_info['bgp_peer.updates_in_out'] = { - 'title': _('Updates'), - 'metrics': [ - ('bgp_peer_outupdates', '-area'), - ('bgp_peer_inupdates', 'area'), - ] -} - -graph_info['bgp_peer.messages_in_out'] = { - 'title': _('Total messages'), - 'metrics': [ - ('bgp_peer_outtotalmessages', '-area'), - ('bgp_peer_intotalmessages', 'area'), - ] -} - -graph_info['bgp_peer.fms_transitions_from_to'] = { - 'title': _('FSM transitions from/to established'), - 'metrics': [ - ('bgp_peer_fsmestablishedtransitions', 'area'), - ], - 'range': (0, 'bgp_peer_fsmestablishedtransitions:max'), -} - - -graph_info['bgp_peer.time_since_last_update'] = { - 'title': _('Time since last update received'), - 'metrics': [ - ('bgp_peer_inupdateelapsedtime', 'area'), - ], - 'range': (0, 'bgp_peer_inupdateelapsedtime:max'), -} - -# juniper prefixes -graph_info['bgp_peer.juniper_prefixes'] = { - 'title': _('Prefixes in/out'), - 'metrics': [ - ('bgp_peer_out_prefixes', '-line'), - ('bgp_peer_in_prefixes_rejected', 'line'), - ('bgp_peer_in_prefixes_active', 'line'), - ('bgp_peer_in_prefixes', 'line'), - ], -} - -# huawei prefixes -graph_info['huawei_bgp_peer_counter'] = { - 'title': _('BGP prefix counter'), - 'metrics': [ - ('bgp_peer_prefixrcvcounter', 'line'), - ('bgp_peer_prefixactivecounter', 'line'), - ('bgp_peer_prefixadvcounter', 'line'), - ] -} - - -###################################################################################################################### -# -# define perf-o-meter for bgp peer uptime + prefixes accepted/advertised -# -###################################################################################################################### - -perfometer_info.append(('stacked', [ - { - 'type': 'logarithmic', - 'metric': 'bgp_peer_fsmestablishedtime', - 'half_value': 2592000.0, # ome month - 'exponent': 2, - }, - { - 'type': 'logarithmic', - 'metric': 'bgp_peer_acceptedprefixes', - 'half_value': 500000.0, - 'exponent': 2, - } -])) - -perfometer_info.append({ - 'type': 'logarithmic', - 'metric': 'bgp_peer_fsmestablishedtime', - 'half_value': 2592000.0, # ome month - 'exponent': 2, -}) diff --git a/source/gui/wato/check_parameters/bgp_peer.py b/source/gui/wato/check_parameters/bgp_peer.py index 32744b040396afac45d450de452d3e772de620ec..812659dc4832a139f4c8e1c183d87ba75a91af73 100644 --- a/source/gui/wato/check_parameters/bgp_peer.py +++ b/source/gui/wato/check_parameters/bgp_peer.py @@ -1,256 +1,4 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# -# License: GNU General Public License v2 -# -# Author: thl-cmk[at]outlook[dot]com -# URL : https://thl-cmk.hopto.org -# Date : 2017-12-25 -# -# Check_MK bgp_peers WATO plugin -# -# 2021-03-27: rewrite for CMK 2.0 -# 2021-08-21: modified for bgp_peer plugin (from cisco_bgp_peer) -# 2021-08-29: removed htmloutput and infotext_values option -# 2022-04-02: added bgp neighbour states -# 2022-04-29: added upper/lower prefix limit -# 2022-05-09: added discovery rule set -# 2022-05-11: added remote_as to build_item -# 2022-09-05: added internal_item to avoid warnings on cmk updates (THX to Jay2k1 for reporting the issue) -# 2023-06-11: moved wato file from ~local/lib/check_mk/gui/plugins/wato -# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters to override the build in wato plugin -# 2024-06-15: fixed typo (no not) -# -# Known issue: the override of the build in wato plugin will break the build in aritsa bgp peer plugin -from cmk.gui.i18n import _ -from cmk.gui.valuespec import ( - Dictionary, - Integer, - TextAscii, - ListOf, - Tuple, - TextUnicode, - MonitoringState, - ListChoice, - TextInput, -) - -from cmk.gui.plugins.wato.utils import ( - CheckParameterRulespecWithItem, - rulespec_registry, - RulespecGroupCheckParametersNetworking, - HostRulespec, - RulespecGroupCheckParametersDiscovery, -) - - -def _parameter_valuespec_bgp_peer(): - return Dictionary( - elements=[ - ('minuptime', - Tuple( - title=_('Minimum uptime for peer'), - orientation='horizontal', - help=_('Set the time in seconds, a peer must be up before the peer is considered sable.'), - elements=[ - Integer(title=_('Warning below'), unit='seconds', default_value=7200, minvalue=0), - Integer(title=_('Critical below'), unit='seconds', default_value=3600, minvalue=0) - ], - )), - ('accepted_prefixes_upper_levels', - Tuple( - title=_('Accepted prefixes upper levels'), - help=_('The values from WATO are preferred to the values from the device.'), - orientation='horizontal', - elements=[ - Integer(title=_('Warning at'), minvalue=0, unit=_('prefixes'), size=5), - Integer(title=_('Critical at'), minvalue=0, unit=_('prefixes'), size=5), - ], - )), - ('accepted_prefixes_lower_levels', - Tuple( - title=_('Accepted prefixes lower levels'), - orientation='horizontal', - elements=[ - Integer(title=_('Warning below'), minvalue=0, unit=_('prefixes'), size=5), - Integer(title=_('Critical below'), minvalue=0, unit=_('prefixes'), size=5), - ], - )), - ('peernotfound', - MonitoringState( - default_value=2, - title=_('State if peer is not found.'), - help=_('Default monitoring state if the peer is not found in the SNMP data') - )), - ('admindown', - MonitoringState( - default_value=1, - title=_('State if peer is admin shutdown.'), - help=_('Monitoring state if the peer is admin shutdown') - )), - ('neighborstate', - Dictionary( - title=_('State to report for BGP neighbor state'), - help=_('Map each BGP state to a CheckMK monitoring state'), - elements=[ - ('1', - MonitoringState( - title=_('1 - idle'), - help=_( - 'This is the first stage of the BGP FSM. BGP detects a start event, tries to initiate a ' - 'TCP connection to the BGP peer, and also listens for a new connect from a peer router. ' - 'If an error causes BGP to go back to the Idle state for a second time, the ' - 'ConnectRetryTimer is set to 60 seconds and must decrement to zero before the connection ' - 'is initiated again. Further failures to leave the Idle state result in the ' - 'ConnectRetryTimer doubling in length from the previous time. ' - 'Default monitoring state is "CRIT"'), - default_value=2, - )), - ('2', - MonitoringState( - title=_('2 - connect'), - help=_( - 'In this state, BGP initiates the TCP connection. If the 3-way TCP handshake completes, ' - 'the established BGP Session BGP process resets the ConnectRetryTimer and sends the Open ' - 'message to the neighbor, and then changes to the OpenSent State.' - 'Default monitoring state is "WARN"'), - default_value=1, - )), - ('3', - MonitoringState( - title=_('3 - active'), - help=_('In this state, BGP starts a new 3-way TCP handshake. If a connection is established, ' - 'an Open message is sent, the Hold Timer is set to 4 minutes, and the state moves to ' - 'OpenSent. If this attempt for TCP connection fails, the state moves back to the Connect ' - 'state and resets the ConnectRetryTimer. ' - 'Default monitoring state is "WARN"'), - default_value=1, - )), - ('4', - MonitoringState( - title=_('4 - opensent'), - help=_( - 'In this state, an Open message has been sent from the originating router and is awaiting ' - 'an Open message from the other router. After the originating router receives the OPEN ' - 'message from the other router, both OPEN messages are checked for errors. If the Open ' - 'messages do not have any errors, the Hold Time is negotiated (using the lower value), ' - 'and a KEEPALIVE message is sent (assuming the value is not set to zero). The connection ' - 'state is then moved to OpenConfirm. If an error is found in the OPEN message, a ' - 'Notification message is sent, and the state is moved back to Idle.' - ' Default monitoring state is "WARN"'), - default_value=1, - )), - ('5', - MonitoringState( - title=_('5 - openconfirm'), - help=_('In this state, BGP waits for a Keepalive or Notification message. Upon receipt of a ' - 'neighbor’s Keepalive, the state is moved to Established. If the hold timer expires, a ' - 'stop event occurs, or a Notification message is received, and the state is moved to ' - 'Idle. ' - 'Default monitoring state is "WARN"'), - default_value=1, - )), - ('6', - MonitoringState( - title=_('6 - established'), - help=_( - 'In this state, the BGP session is established. BGP neighbors exchange routes via Update ' - 'messages. As Update and Keepalive messages are received, the Hold Timer is reset. If the ' - 'Hold Timer expires, an error is detected and BGP moves the neighbor back to the Idle ' - 'state. ' - 'Default monitoring state is "OK"'), - default_value=0, - )), - ])), - ('noprefixlimit', - MonitoringState( - default_value=1, - title=_('State if no admin prefix limit/warn threshold is configured.'), - help=_('The admin prefix limit and warn threshold needs to be configured on the device. ' - 'For example: "neighbor 172.17.10.10 maximum-prefix 10000 80". The threshold is in percentage ' - 'of the prefix limit.') - )), - ('peer_list', - ListOf( - Tuple( - orientation='horizontal', - elements=[ - TextUnicode( - title=_('BGP Peer'), - help=_('The configured value must match a BGP item reported by the monitored ' - 'device. For example: "10.194.115.98" or "2A10:1CD0:1020:135::20 IPv6 Unicast"'), - allow_empty=False, - size=50, - ), - TextUnicode( - title=_('BGP Peer Alias'), - help=_('You can configure an individual alias here for the BGP peer matching ' - 'the text configured in the "BGP Peer IP-address" field. The alias will ' - 'be shown in the check info'), - size=50, - ), - MonitoringState( - default_value=2, - title=_('State if not found'), - help=_('You can configure an individual state if the BGP peer matching the text ' - 'configured in the "BGP Peer IP-address" field is not found') - ), - ]), - add_label=_('Add BGP peer'), - movable=False, - title=_('BGP Peers'), - )), - ('internal_item', # added by plugin discovery function - TextUnicode()), - ], - hidden_keys=['internal_item'], - ) - - -rulespec_registry.register( - CheckParameterRulespecWithItem( - check_group_name='bgp_peer', - group=RulespecGroupCheckParametersNetworking, - item_spec=lambda: TextInput(title=_('BGP peer'), ), - match_type='dict', - parameter_valuespec=_parameter_valuespec_bgp_peer, - title=lambda: _('BGP peer'), - )) - - -def _valuespec_discovery_bgp_peer(): - item_parts = [ - # ('remote_address', 'Peer remote address'), - ('remote_as', 'Remote AS'), - ('address_family', 'Address family'), - ('routing_instance', 'Routing instance/VRF'), - - ] - return Dictionary( - title=_('BGP peer'), - elements=[ - ('build_item', - ListChoice( - title=_('Information not to use in the item name'), - help=_( - 'The Peer remote address is always used as the item name. By default the check will add the ' - 'address-family and the routing instance/VRF if available. You can decide to not use these ' - 'additional information in the item name. Do so only if your peers have only one address-' - 'family configured and you don\'t have the same peer remote address in different routing ' - 'instances/VRFs configured.' - ), - choices=item_parts, - default_value=['remote_as'], - )), - ], - ) - - -rulespec_registry.register( - HostRulespec( - group=RulespecGroupCheckParametersDiscovery, - match_type='dict', - name='discovery_bgp_peer', - valuespec=_valuespec_discovery_bgp_peer, - )) +# dummy to shadow build in bgp peer rule set \ No newline at end of file diff --git a/source/gui/wato/check_parameters/inv_bgp_peer.py b/source/gui/wato/check_parameters/inv_bgp_peer.py deleted file mode 100644 index e728182a2fddb8aa1d85e7c0a63a8e99bc2dfafa..0000000000000000000000000000000000000000 --- a/source/gui/wato/check_parameters/inv_bgp_peer.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# Author: thl-cmk[at]outlook[dot]com -# URL : https://thl-cmk.hopto.org -# Date : 2022-04-24 -# -# 2022-04-24: added option for BGP down time -# added option to remove some columns from inventory -# 2022-04-28: added Whois options -# 2023-06-12: moved wato file from ~local/lib/check_mk/gui/plugins/wato -# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters - -from cmk.gui.i18n import _ -from cmk.gui.plugins.wato.utils import ( - HostRulespec, - rulespec_registry, -) -from cmk.gui.valuespec import ( - Dictionary, - ListChoice, - Age, - DropdownChoice, - Integer, -) - -from cmk.gui.plugins.wato.inventory import ( - RulespecGroupInventory, -) - - -def _valuespec_inv_bgp_peer(): - removecolumns = [ - # ('remote_as', 'Remote AS'), - # ('remote_id', 'Remote ID'), - # ('local_addr', 'Local address'), - # ('local_as', 'Local AS'), - # ('local_id', 'Local ID'), - ('address_family', 'Address family'), - ('last_error', 'Last error'), - ('last_error_code', 'Last error code'), - # ('prev_state', 'Previous state'), - ('as_name', 'Remote AS name'), - ('as_org_name', 'Remote AS Org Name'), - ('bgp_type', 'Type'), - ('version', 'Version'), - ] - - return Dictionary( - title=_('BGP peer'), - elements=[ - ('not_in_service_time', - Age( - title=_('Time peer is not up until considered not in service'), - default_value=2592000, # 30 days in seconds, - )), - ('remove_columns', - ListChoice( - title=_('List of columns to remove'), - help=_('Information to remove from inventory'), - choices=removecolumns, - default_value=[], - )), - ('whois_enable', - Dictionary( - title=_('Add whois data to the inventory'), - help=_( - 'The whois data will be fetched via RDAP from the registries. For this the the plugin tries to' - 'find the best registry via the RDAP bootstrap data from https://data.iana.org/rdap/asn.json.' - 'The query it self will go to the found registry via http(s). Note: the request might be get ' - 'redirected if there a different authoritative registry for the ASn' - ), - elements=[ - ('whois_rir', - DropdownChoice( - title='Preferred RIR to fetch whois data', - help=_( - 'This registry will be used if the plugin can not determine the authoritative registry ' - 'based on the bootstrap data.' - ), - choices=[ - ('afrinic', _('AFRINIC (https://rdap.afrinic.net/rdap)')), - ('apnic', _('APNIC (https://rdap.apnic.net)')), - ('arin', _('ARIN (https://rdap.arin.net/registry)')), - ('ripe', _('RIPE (https://rdap.db.ripe.net)')), - ('lacnic', _('LACNIC (https://rdap.apnic.net)')), - ] - )), - ('whois_timeout', - Integer( - title='Timeout for connections to RIRs', - help=_('The connection timeout for each whois request.'), - default_value=5, - minvalue=1, - unit=_('seconds'), - )), - ] - )), - ], - ) - - -rulespec_registry.register( - HostRulespec( - group=RulespecGroupInventory, - match_type='dict', - name='inv_parameters:inv_bgp_peer', - valuespec=_valuespec_inv_bgp_peer, - )) diff --git a/source/packages/bgp_peer b/source/packages/bgp_peer index 0bc57580780d775fbcbabcaa0150927d0a8405cc..a8979990117c3c59074a41280efcf6eb2ca52e14 100644 --- a/source/packages/bgp_peer +++ b/source/packages/bgp_peer @@ -27,17 +27,19 @@ 'https://thl-cmk.hopto.org/gitlab/checkmk/juniper-networks/juniper_bgp_peer\n' '\n', 'download_url': 'https://thl-cmk.hopto.org/vendor-independent/bgp_peer', - 'files': {'agent_based': ['bgp_peer.py', - 'inv_bgp_peer.py', - 'utils/bgp_peer.py'], - 'checkman': ['bgp_peer'], - 'gui': ['metrics/bgp_peer.py', - 'wato/check_parameters/bgp_peer.py', - 'wato/check_parameters/inv_bgp_peer.py'], + 'files': {'agent_based': ['bgp_peer.py'], + 'cmk_addons_plugins': ['bgp_peer/agent_based/bgp_peer.py', + 'bgp_peer/agent_based/inv_bgp_peer.py', + 'bgp_peer/graphing/bgp_peer.py', + 'bgp_peer/lib/bgp_peer.py', + 'bgp_peer/rulesets/bgp_peer.py', + 'bgp_peer/rulesets/inv_bgp_peer.py', + 'bgp_peer/checkman/bgp_peer'], + 'gui': ['wato/check_parameters/bgp_peer.py'], 'web': ['plugins/views/inv_bgp_peer.py']}, 'name': 'bgp_peer', 'title': 'BGP Peer', - 'version': '2.2.8-20250117', + 'version': '2.3.0-20250329', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', - 'version.usable_until': '2.4.0b1'} + 'version.usable_until': '2.5.0b1'}