From 1c4469b406869299b3a82886b115a45238cbb069 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Fri, 17 Feb 2023 10:20:34 +0100 Subject: [PATCH] update project --- CHANGELOG | 2 + agent_based/bgp_peer.py | 7 +- bgp_peer.mkp | Bin 15602 -> 15627 bytes gui/metrics/bgp_peer.py | 225 ++++++++++++++++++++++++++++++++++ gui/views/inv_bgp_peer.py | 58 +++++++++ gui/wato/bgp_peer.py | 250 ++++++++++++++++++++++++++++++++++++++ gui/wato/inv_bgp_peer.py | 107 ++++++++++++++++ packages/bgp_peer | 17 ++- 8 files changed, 654 insertions(+), 12 deletions(-) create mode 100644 gui/metrics/bgp_peer.py create mode 100644 gui/views/inv_bgp_peer.py create mode 100644 gui/wato/bgp_peer.py create mode 100644 gui/wato/inv_bgp_peer.py diff --git a/CHANGELOG b/CHANGELOG index 4a8c47b..9e210a7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -30,3 +30,5 @@ 2023-01-21: changed to always yield fsm_established_time (not only if beep connects, but also on all other states) 2023-01-20: add description to BgpPeerItem (for Arista) 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) diff --git a/agent_based/bgp_peer.py b/agent_based/bgp_peer.py index 0427531..7e9e957 100644 --- a/agent_based/bgp_peer.py +++ b/agent_based/bgp_peer.py @@ -28,7 +28,8 @@ # 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) # Example Agent Output: # BGP4-MIB @@ -251,8 +252,8 @@ register.check_plugin( 'peernotfound': 2, 'admindown': 1, 'noprefixlimit': 1, - 'accepted_prefixes_upper_levels': (None, None), - 'accepted_prefixes_lower_levels': (None, None), + # 'accepted_prefixes_upper_levels': (None, None), # Type error in discovery (cmk2.1 GUI only) + # 'accepted_prefixes_lower_levels': (None, None), # Type error in discovery (cmk2.1 GUI only) 'neighborstate': { '1': 2, # idle '2': 1, # connect diff --git a/bgp_peer.mkp b/bgp_peer.mkp index da9a24373c17cd78858b14befdcab5aabc16efee..aa3427a79c6ed30fcb8153f682e49be73db15190 100644 GIT binary patch literal 15627 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 O<idmK50E)9(Ek97aZ|Sd literal 15602 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 diff --git a/gui/metrics/bgp_peer.py b/gui/metrics/bgp_peer.py new file mode 100644 index 0000000..6db6b16 --- /dev/null +++ b/gui/metrics/bgp_peer.py @@ -0,0 +1,225 @@ +#!/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 +# +# +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', +} + + +###################################################################################################################### +# +# 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:mac'), +} + +# 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'), + ], +} + +###################################################################################################################### +# +# 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/gui/views/inv_bgp_peer.py b/gui/views/inv_bgp_peer.py new file mode 100644 index 0000000..f67054c --- /dev/null +++ b/gui/views/inv_bgp_peer.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from cmk.gui.i18n import _ +from cmk.gui.plugins.views.utils import ( + inventory_displayhints, +) +from cmk.gui.plugins.visuals.inventory import ( + FilterInvtableAdminStatus, + FilterInvtableTimestampAsAge, + FilterInvBool, +) +from cmk.gui.plugins.views.inventory import declare_invtable_view + +inventory_displayhints.update({ + '.networking.bgp_peers:': { + 'title': _('BGP Peers'), + 'keyorder': [ + 'remote_addr', + 'peer_state', 'last_change', 'in_service', + 'local_addr', 'remote_id', 'local_id', 'remote_as', 'local_as', + ], + 'view': 'invbgppeer_of_host', + }, + '.networking.bgp_peers:*.remote_addr': {'title': _('Remote address'), }, + '.networking.bgp_peers:*.local_addr': {'title': _('Local address'), }, + '.networking.bgp_peers:*.remote_id': {'title': _('Remote ID'), }, + '.networking.bgp_peers:*.local_id': {'title': _('Local ID'), }, + '.networking.bgp_peers:*.remote_as': {'title': _('Remote AS'), }, + '.networking.bgp_peers:*.local_as': {'title': _('Local AS'), }, + '.networking.bgp_peers:*.bgp_type': {'title': _('Type'), }, + '.networking.bgp_peers:*.version': {'title': _('Version'), }, + '.networking.bgp_peers:*.last_error': {'title': _('Last error'), }, + '.networking.bgp_peers:*.last_error_code': {'title': _('Last error code'), }, + '.networking.bgp_peers:*.address_family': {'title': _('Address family'), }, + '.networking.bgp_peers:*.as_name': {'title': _('Remote AS Name'), }, + '.networking.bgp_peers:*.as_org_name': {'title': _('Remote AS Org Name'), }, + '.networking.bgp_peers:*.peer_state': { + 'title': _('Peer state'), + 'short': _('State'), + 'paint': 'if_admin_status', + 'filter': FilterInvtableAdminStatus, + }, + '.networking.bgp_peers:*.in_service': { + 'title': _('In service'), + 'short': _('In service'), + 'paint': 'bool', + # 'filter': FilterInvBool, + }, + '.networking.bgp_peers:*.last_change': { + 'title': _('Last change'), + 'short': _('Last change'), + 'paint': 'timestamp_as_age_days', + 'filter': FilterInvtableTimestampAsAge, + }, +}) + +declare_invtable_view('invbgppeer', '.networking.bgp_peers:', _('BGP peers'), _('BGP peers')) diff --git a/gui/wato/bgp_peer.py b/gui/wato/bgp_peer.py new file mode 100644 index 0000000..8148970 --- /dev/null +++ b/gui/wato/bgp_peer.py @@ -0,0 +1,250 @@ +#!/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) + +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + Integer, + TextAscii, + ListOf, + Tuple, + TextUnicode, + MonitoringState, + ListChoice, +) + +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 no 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: TextAscii(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, + )) diff --git a/gui/wato/inv_bgp_peer.py b/gui/wato/inv_bgp_peer.py new file mode 100644 index 0000000..f4832c6 --- /dev/null +++ b/gui/wato/inv_bgp_peer.py @@ -0,0 +1,107 @@ +#!/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 + +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/packages/bgp_peer b/packages/bgp_peer index c76af23..abed79f 100644 --- a/packages/bgp_peer +++ b/packages/bgp_peer @@ -13,14 +13,13 @@ 'inv_bgp_peer.py', 'utils/bgp_peer.py'], 'checkman': ['bgp_peer'], - 'web': ['plugins/metrics/bgp_peer.py', - 'plugins/views/inv_bgp_peer.py', - 'plugins/wato/bgp_peer.py', - 'plugins/wato/inv_bgp_peer.py']}, + 'gui': ['metrics/bgp_peer.py', + 'views/inv_bgp_peer.py', + 'wato/bgp_peer.py', + 'wato/inv_bgp_peer.py']}, 'name': 'bgp_peer', - 'num_files': 8, - 'title': 'BGP Peer State Check', - 'version': '20230123.v1.9', - 'version.min_required': '2.0.0', - 'version.packaged': '2021.09.20', + 'title': 'BGP Peer', + 'version': '20230217.v2.0.0', + 'version.min_required': '2.1.0', + 'version.packaged': '2.1.0p21', 'version.usable_until': None} \ No newline at end of file -- GitLab