Collection of CheckMK checks (see https://checkmk.com/). All checks and plugins are provided as is. Absolutely no warranty. Send any comments to thl-cmk[at]outlook[dot]com

Skip to content
Snippets Groups Projects
Commit e56b8511 authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

update project

parent c163610a
No related branches found
No related tags found
No related merge requests found
......@@ -9,13 +9,6 @@
#
# Monitor status of Cisco BGP Peers (IPv4 and IPv6)
#
# ToDo: move longoutput to inventory, based on inv_bgp_peer
# ToDo: move helper functions to utils/bgp_peer, merge with bgp_peer
# ToDo: merge WATO with bgp_peer
# ToDo: merge metrics with bgp_peer
# ToDo: merge check function with bgp_peer
# goal: only snmp_section and parse function left
#
# 2018-05-24: changed counters to 1/s
# 2018-05-25: a lot of code cleanup
# packet name changed from cisco_bgp to cisco_bgp_peer
......@@ -39,7 +32,7 @@
# thanks to Florian[dot]Dille[at]aldi-sued[dot]com and timhor[at]outlook[dot]com
# added type hinting for parsed data (section)
# optimised data handling in check function (add prefixes to peer info)
# made default state if item not found configurable via WALO
# made default state if item not found configurable via WATO
# 2021-07-21: fixed missing oid_end in parse function, thanks to oliverj@cmkforum
# 2021-08-18: fixed counter rollover, changed detect section to find only BGP enabled devices.
# 2012-08-20: cleanup, optimized parse function
......@@ -47,258 +40,55 @@
# 2021-08-23: changed service name from "Cisco BGP peer" to "BGP peer" --> streamline with bgp_peer
# get localas from BGP-4-MIB::bgpLocalAs if CISCO-BGP4-MIB::cbgpPeer2LocalAs not set
# 2021-08-29: fixed bgpLocalAs in BGP-4-MIB not set
# 2021-11-08: moved helper functions to utils/bgp_peer
# moved longoutput/details to inventory based on inv_bgp_beer
# merged WATO with bgp_peer
# merged METRICS with bgp_peer
# 2021-11-13: fix for mixed peers (with and without prefixes on one host)
# 2021-11-14: merged check function with bgp_peer
# merged parse function with bgp_peer
import re
import time
from dataclasses import dataclass
from typing import List, Dict, TypedDict, Optional, Tuple
from typing import List, Dict
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
register,
Service,
Result,
check_levels,
State,
SNMPTree,
exists,
contains,
all_of,
exists,
OIDEnd,
get_rate,
GetRateError,
get_value_store,
Metric,
render,
)
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
DiscoveryResult,
CheckResult,
StringTable,
)
@dataclass
class Peer(TypedDict):
remoteaddr: str
localaddr: str
localid: str
remoteid: str
localas: Optional[int]
remoteas: Optional[int]
adminstate: Optional[int]
state: Optional[int]
lasterror: str
lasterrortxt: str
prevstate: Optional[int]
perfdata_rate: List[Tuple[str, int]]
perfdata_count: List[Tuple[str, int]]
fsmestablishedtime: Optional[int]
addrfamilyname: Optional[str]
prefixadminlimit: Optional[int]
prefixthreshold: Optional[int]
prefixclearthreshold: Optional[int]
acceptedprefixes: Optional[int]
###########################################################################
#
# Helper functions
#
###########################################################################
def _bgp_render_ipv4_address(bytestring):
return '.'.join([f'{ord(m)}' for m in bytestring])
def _bgp_shorten_ipv6_adress(address):
address = address.split(':')
span = 2
address = [''.join(address[i:i + span]) for i in range(0, len(address), span)]
for m in range(0, len(address)):
address[m] = re.sub(r'^0{1,3}', r'', address[m])
address = ':'.join(address)
zeros = ':0:0:0:0:0:0:'
while not zeros == '':
if zeros in address:
address = re.sub(r'%s' % zeros, r'::', address)
zeros = ''
else:
zeros = zeros[:-2]
return address
def _bgp_render_ipv6_address(bytestring):
address = ":".join(["%02s" % hex(ord(m))[2:] for m in bytestring]).replace(' ', '0').upper()
address = _bgp_shorten_ipv6_adress(address)
return address
def _bgp_render_ip_address(bytestring):
if len(bytestring) == 4:
return _bgp_render_ipv4_address(bytestring)
elif len(bytestring) == 16:
return _bgp_render_ipv6_address(bytestring)
else:
return ''
def _cisco_bgp_get_peer(OID_END):
# returns peer address string from OID_END
# u'1.4.217.119.208.34.1.1' --> 217.119.208.34
# u'2.20.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1' --> 42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17
peer_ip = ''
OID_END = OID_END.split('.')
if int(OID_END[1]) == 4: # length of ip address
peer_ip = '.'.join(OID_END[2:6]) # ipv4 address
elif int(OID_END[1]) == 16: # ipv6 address
peer_ip = ':'.join('%02s' % hex(int(m))[2:] for m in OID_END[2:18]).replace(' ', '0').upper()
peer_ip = _bgp_shorten_ipv6_adress(peer_ip)
return peer_ip
def _cisco_bgp_errors(bytestring):
lasterrorhex = ''.join([f'{ord(x):02X} ' for x in bytestring]).strip()
byte1, byte2 = lasterrorhex.split()
names = {}
names[0] = {0: 'NO ERROR'}
names[1] = {0: 'Message',
2: 'Connection Not Synchronized',
3: 'Bad Message Length',
4: 'Bad Message Type',
}
names[2] = {0: 'OPEN',
1: 'Unsupported Version Number',
2: 'Bad Peer AS',
3: 'Bad BGP Identifier',
4: 'Unsupported Optional Parameter',
5: 'Authentication Failure',
6: 'Unacceptable Hold',
}
names[3] = {0: 'UPDATE',
1: 'Malformed Attribute List',
2: 'Unrecognized Well-known Attribute',
3: 'Missing Well-known Attribute',
4: 'Attribute Flags Error',
5: 'Attribute Length Error',
6: 'Invalid ORIGIN Attribute',
7: 'AS Routing Loop',
8: 'Invalid NEXT_HOP Attribute',
9: 'Optional Attribute Error',
10: 'Invalid Network Field',
11: 'Malformed AS_PATH',
}
names[4] = {0: 'Hold Timer Expired', }
names[5] = {0: 'Finite State Machine Error', }
names[6] = {0: 'Administratively Shutdown',
1: 'Max Prefix Reached',
2: 'Peer Unconfigured',
3: 'Administratively Reset',
4: 'Connection Rejected',
5: 'Other Configuration Change',
}
return names[int(byte1, 16)].get(int(byte2, 16))
def _cisco_bgp_adminstate(state):
names = {
1: 'shutdown',
2: 'enabled',
}
return names.get(state, f'unknown ({state})')
def _cisco_bgp_peerstate(state):
names = {
0: 'none',
1: 'idle',
2: 'connect',
3: 'active',
4: 'opensned',
5: 'openconfirm',
6: 'established'
}
return names.get(state, f'unknown ({state})')
from cmk.base.plugins.agent_based.utils.bgp_peer import (
bgp_peerstate,
bgp_errors,
bgp_render_ip_address,
bgp_get_peer,
ByteToHex,
BgpPeer,
bgp_get_peer_entry,
)
###########################################################################
#
# DATA Parser function
# cisco_bgp_peer (CISCO-BGP4-MIB:cbgpPeer2Entry)
#
###########################################################################
def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Dict[str, Peer]:
cbgpPeer2Entry, cbgpPeer2AddrFamily, bgpLocalAs = string_table
# local as from BGP-4-MIB
try:
bgpLocalAs = bgpLocalAs[0][0]
except (IndexError):
bgpLocalAs = 'N/A'
def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer]:
cbgpPeer2Entry, cbgpPeer2AddrFamily = string_table
# create dictionary from cbgpPeer2Entry (peer ip address as index)
peer_table = {}
for entry in cbgpPeer2Entry:
oid_end, state, adminstatus, localaddr, localas, localidentifier, remoteas, remoteidentifier, inupdates, \
outupdates, intotalmessages, outtotalmessages, lasterror, fsmestablishedtransitions, fsmestablishedtime, \
inupdateelapsedtime, lasterrortxt, prevstate = entry
if localas == '0' and bgpLocalAs != '0':
localas = bgpLocalAs
if not oid_end == '':
peer = {
'remoteaddr': _cisco_bgp_get_peer(oid_end),
'localaddr': _bgp_render_ip_address(localaddr),
'localid': localidentifier,
'remoteid': remoteidentifier,
'lasterror': _cisco_bgp_errors(lasterror),
'lasterrortxt': lasterrortxt,
'prevstate': _cisco_bgp_peerstate(prevstate),
'perfdata_rate': [],
'perfdata_count': [],
}
for key, value in [
('state', state),
('adminstate', adminstatus),
('localas', localas),
('remoteas', remoteas),
('fsmestablishedtime', fsmestablishedtime),
]:
try:
peer[key] = int(value)
except ValueError:
pass
for key, value in [
('inupdates', inupdates),
('outupdates', outupdates),
('intotalmessages', intotalmessages),
('outtotalmessages', outtotalmessages),
]:
try:
peer['perfdata_rate'].append((key, int(value)))
except ValueError:
pass
for key, value in [
('fsmestablishedtransitions', fsmestablishedtransitions),
('fsmestablishedtime', fsmestablishedtime),
('inupdateelapsedtime', inupdateelapsedtime),
]:
try:
peer['perfdata_count'].append((key, int(value)))
except ValueError:
pass
peer_table.update({f'{_cisco_bgp_get_peer(oid_end)}': peer})
entry[0] = bgp_get_peer(entry[0]) # replace OID_END with remote address
bgp_peer = bgp_get_peer_entry(entry)
if bgp_peer:
peer_table.update(bgp_peer)
prefixes_table = {}
# create dictionary from cbgpPeer2AddrFamily (with 'remoteip addrfamilyname' as index)
......@@ -308,23 +98,13 @@ def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Dict[str, Peer]:
if not oid_end == '':
remoteaddr = _cisco_bgp_get_peer(oid_end)
remoteaddr = bgp_get_peer(oid_end)
# merge peer info with prefixes
prefixes = peer_table[remoteaddr].copy()
prefixes.update({
'addrfamilyname': addrfamilyname
})
for key, value in [
('prefixadminlimit', prefixadminlimit),
('prefixthreshold', prefixthreshold),
('prefixclearthreshold', prefixclearthreshold),
('acceptedprefixes', acceptedprefixes),
]:
try:
prefixes[key] = int(value)
except ValueError:
pass
prefixes = peer_table[remoteaddr]
prefixes.prefix_admin_limit = int(prefixadminlimit) if prefixadminlimit.isdigit() else None
prefixes.accepted_prefixes = int(acceptedprefixes) if acceptedprefixes.isdigit() else None
prefixes.prefix_clear_threshold = int(prefixclearthreshold) if prefixclearthreshold.isdigit() else None
prefixes.prefix_threshold = int(prefixthreshold) if prefixthreshold.isdigit() else None
for key, value in [
('advertisedprefixes', advertisedprefixes),
......@@ -333,185 +113,30 @@ def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Dict[str, Peer]:
('withdrawnprefixes', withdrawnprefixes),
]:
try:
prefixes['perfdata_rate'].append((key, int(value)))
prefixes.metric_rate.append((key, int(value)))
except ValueError:
pass
prefixes_table.update({f'{remoteaddr} {addrfamilyname}': prefixes})
if prefixes_table:
for peer in peer_table.keys():
no_address_family = False
for address_family in prefixes_table.keys():
if address_family.startswith(peer):
no_address_family = True
break
if not no_address_family:
prefixes_table.update({peer:peer_table[peer]})
return prefixes_table
else:
return peer_table
###########################################################################
#
# INVENTORY function
#
###########################################################################
def discovery_cisco_bgp_peer(section: Dict[str, Peer]) -> DiscoveryResult:
for key in section.keys():
yield Service(item=key)
###########################################################################
#
# CHECK function
#
###########################################################################
def check_cisco_bgp_peer(item, params, section: Dict[str, Peer]) -> CheckResult:
# read params
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: Peer = section[item]
except KeyError:
yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data')
return
if peer.get('localas') == 0:
peer.update({'localas': params.get('useaslocalas', 0)})
if not peer['adminstate'] == 2: # not start
yield Result(state=State(params['admindown']), summary=f'Admin state: {_cisco_bgp_adminstate(peer["adminstate"])}')
else:
if peer['state'] == 1: # idle
yield Result(state=State.CRIT, summary=f'Peer state: {_cisco_bgp_peerstate(peer["state"])}')
elif peer['state'] == 6: # established
yield from check_levels(
value=peer['fsmestablishedtime'],
label='Uptime',
levels_lower=params['minuptime'],
render_func=render.timespan
)
else: # everything else
yield Result(state=State.WARN, summary=f'Peer state: {_cisco_bgp_peerstate(peer["state"])}')
bgptype = ''
if not peer.get('localas') == 0:
if peer.get('remoteas') == peer.get('localas'):
bgptype = ' (iBGP)'
else:
bgptype = ' (eBGP)'
longoutput_data = [
['', 'Local', 'Remote'],
['IP-address', peer.get('localaddr'), peer.get('remoteaddr')],
['Router-ID', peer.get('localid'), peer.get('remoteid')],
['Autonomus System', peer.get('localas'), str(peer.get('remoteas')) + bgptype],
['State', _cisco_bgp_peerstate(peer["state"]), ''],
['Admin state', _cisco_bgp_adminstate(peer["adminstate"]), ''],
['Last error', peer.get('lasterror'), ''],
['Last error text', peer.get('lasterrortxt'), ''],
['Previous state', peer.get('prevstate'), ''],
['Address family name', peer.get('addrfamilyname', 'unknown'), ''],
]
acceptedprefixes = peer.get('acceptedprefixes')
prefixadminlimit = peer.get('prefixadminlimit')
prefixthreshold = peer.get('prefixthreshold')
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
longoutput_data.append(['Prefix clear threshold (%)', peer.get('prefixclearthreshold', ''), ''])
longoutput_data.append(['Prefix admin limit (prefixes)', f'{prefixadminlimit:d}', ''])
longoutput_data.append(['Prefix threshold (prefixes/%)', f'{warnthreshold:d} / {prefixthreshold:d}', f''])
elif acceptedprefixes is not None:
yield Result(
state=State(params['noprefixlimit']),
notice='Prefix limit/warn threshold: not configured on the device.',
)
warnthreshold = None
if params.get('htmloutput', False):
#
# disable 'Escape HTML codes in plugin output' in wato --> global settings
#
table_bracket = '<table border="1">%s</table>'
line_bracket = '<tr>%s</tr>'
cell_bracket = '<td>%s</td><td>%s</td><td>%s</td>'
cell_seperator = ''
longoutput = '\n' + table_bracket % (''.join(
[line_bracket % cell_seperator.join([cell_bracket % (entry[0], entry[1], entry[2])]) for entry in
longoutput_data]))
else:
longoutput = '\nfor nicer output' \
'\ndisable \'Escape HTML codes in plugin output\' in wato -> ' \
'global settings and enable HTML output in \'Parameters for this service\' or' \
'\n add a Rule to the \'Cisco BGP peer\' service (Setup - Services - Service monitoring ' \
'rules - Escape HTML in service output.'
for entry in longoutput_data:
if not entry[2] == '':
longoutput += f'\n{entry[0]}: {entry[1]} / {entry[2]}'
else:
longoutput += f'\n{entry[0]}: {entry[1]}'
if peer['adminstate'] == 2: # no perfdata if admin shutdown
if acceptedprefixes is not None:
yield from check_levels(
value=acceptedprefixes,
metric_name='cisco_bgp_peer_acceptedprefixes',
levels_upper=(warnthreshold, prefixadminlimit),
label='Prefixes accepted',
render_func=lambda v: f'{v}'
)
now_time = time.time()
value_store = get_value_store()
for entry in peer['perfdata_rate']:
key, value = entry
try:
value = get_rate(value_store, f'{key}', now_time, value, raise_overflow=True)
except GetRateError:
value = 0
yield Metric(name=f'cisco_bgp_peer_{key}', value=value, boundaries=(0, None))
for entry in peer['perfdata_count']:
key, value = entry
yield Metric(name=f'cisco_bgp_peer_{key}', value=value, boundaries=(0, None))
# add optional infotext values
for key, text in [
('remoteid', 'Remote ID:'),
('remoteas', 'Remote AS:'),
('localaddr', 'Local address:'),
('localid', 'Local ID:'),
('localas', 'Local AS:'),
]:
if key in params['infotext_values']:
try:
yield Result(state=State.OK, summary=f'{text} {peer[key]}', details=' ')
except KeyError:
pass
# write longoutput at last for clean output
yield Result(state=State.OK, notice=longoutput)
###########################################################################
#
# CHECK info
#
###########################################################################
register.snmp_section(
name='cisco_bgp_peer',
parse_function=parse_cisco_bgp_peer,
parsed_section_name='bgp_peer',
supersedes=['bgp_peer'],
fetch=[
SNMPTree(
......@@ -520,21 +145,13 @@ register.snmp_section(
OIDEnd(),
'3', # cbgpPeer2State
'4', # cbgpPeer2AdminStatus
'6', # cbgpPeer2LocalAddr
'8', # cbgpPeer2LocalAs -> empty
'9', # cbgpPeer2LocalIdentifier
'11', # cbgpPeer2RemoteAs
'12', # cbgpPeer2RemoteIdentifier
'13', # cbgpPeer2InUpdates
'14', # cbgpPeer2OutUpdates
'15', # cbgpPeer2InTotalMessages
'16', # cbgpPeer2OutTotalMessages
'17', # cbgpPeer2LastError
'18', # cbgpPeer2FsmEstablishedTransitions
'19', # cbgpPeer2FsmEstablishedTime
'27', # cbgpPeer2InUpdateElapsedTime
'28', # cbgpPeer2LastErrorTxt
'29', # cbgpPeer2PrevState
]
),
SNMPTree(
......@@ -554,6 +171,120 @@ register.snmp_section(
'8.1.8', # cbgpPeer2WithdrawnPrefixes
]
),
],
detect=all_of(
contains('.1.3.6.1.2.1.1.1.0', 'Cisco'),
exists('.1.3.6.1.4.1.9.9.187.1.2.5.1.3.*')
),
)
###########################################################################
#
# INVENTORY Plugin inv_cisco_bgp_peer (CISCO-BGP4-MIB::cbgpPeer2Entry)
#
###########################################################################
def parse_inv_cisco_bgp_peer(string_table: List[StringTable]):
peers, address_family, base = string_table
bgp_peers = []
# convert families from list to dict
# [
# ['1.4.77.235.182.229.1.1', 'IPv4 Unicast'],
# ['1.4.217.119.208.2.1.1', 'IPv4 Unicast'],
# ['1.4.217.119.208.34.1.1', 'IPv4 Unicast'],
# ['2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1.2.1', 'IPv6 Unicast'],
# ['2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1', 'IPv6 Unicast']
# ]
#
# {
# '1.4.77.235.182.229.1.1': 'IPv4 Unicast',
# '1.4.217.119.208.2.1.1': 'IPv4 Unicast',
# '1.4.217.119.208.34.1.1': 'IPv4 Unicast',
# '2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1.2.1': 'IPv6 Unicast',
# '2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1': 'IPv6 Unicast'
# }
peer_families = dict(map(lambda x: (x[0], x[1]), address_family))
for entry in peers:
try:
oid_end, local_addr, local_as, local_id, remote_as, remote_id, last_error, last_errortxt, \
prev_state = entry
except ValueError:
return
if local_as == '0':
try:
local_as = base[0][0]
except (ValueError, IndexError):
local_as = 'N/A'
address_families = []
for key in peer_families:
if key.startswith(oid_end):
address_families.append(peer_families[key])
peer = {
'remote_addr': bgp_get_peer(oid_end),
'remote_id': remote_id,
'version': '4',
'local_addr': bgp_render_ip_address(local_addr),
'remote_as': remote_as,
'local_as': local_as,
'local_id': local_id,
'status_columns': {
'last_error_code': ByteToHex(last_error),
'last_error': bgp_errors(last_error),
},
'prev_state': bgp_peerstate(prev_state),
}
if local_as.isdigit():
if local_as == remote_as:
peer['bgp_type'] = 'iBGP'
else:
peer['bgp_type'] = 'eBGP'
else:
peer['bgp_type'] = 'N/A'
if address_families:
peer['address_family'] = ','.join(address_families)
bgp_peers.append(peer)
return bgp_peers
register.snmp_section(
name='inv_cisco_bgp_peer',
parse_function=parse_inv_cisco_bgp_peer,
parsed_section_name='inv_bgp_peer',
supersedes=['inv_bgp_peer'],
fetch=[
SNMPTree(
base='.1.3.6.1.4.1.9.9.187.1.2.5.1', # CISCO-BGP4-MIB::cbgpPeer2Entry
oids=[
OIDEnd(),
'6', # cbgpPeer2LocalAddr
'8', # cbgpPeer2LocalAs -> empty
'9', # cbgpPeer2LocalIdentifier
'11', # cbgpPeer2RemoteAs
'12', # cbgpPeer2RemoteIdentifier
'17', # cbgpPeer2LastError
'28', # cbgpPeer2LastErrorTxt
'29', # cbgpPeer2PrevState
]
),
SNMPTree(
base='.1.3.6.1.4.1.9.9.187.1.2', # cbgpPeer
oids=[
OIDEnd(), #
'7.1.3', # cbgpPeer2AddrFamilyName
]
),
SNMPTree(
base='.1.3.6.1.2.1.15', # BGP-4-MIB
oids=[
......@@ -566,21 +297,3 @@ register.snmp_section(
exists('.1.3.6.1.4.1.9.9.187.1.2.5.1.3.*')
),
)
register.check_plugin(
name='cisco_bgp_peer',
service_name='BGP peer %s',
discovery_function=discovery_cisco_bgp_peer,
check_function=check_cisco_bgp_peer,
check_default_parameters={
'minuptime': (7200, 3600),
'useaslocalas': 0,
'htmloutput': False,
'noprefixlimit': 1,
'infotext_values': [],
'peer_list': [],
'admindown': 1,
'peernotfound': 2,
},
check_ruleset_name='cisco_bgp_peer',
)
No preview for this file type
......@@ -8,20 +8,25 @@
'\n'
'v0.2: added support for more then one address family per '
'peer\n'
' changed item from peer address to peer address + '
' changed item from peer address to peer address + '
'address family\n'
" changed package name from 'cisco_bgp' to "
" changed package name from 'cisco_bgp' to "
"'cisco_bgp_peer'\n"
'v0.3: rewrite for CMK 2.0\n',
'v0.3: rewrite for CMK 2.0\n'
'v0.4: moved static output (details/long output) to the '
'inventory, helper functions, wato, metrics and inventory '
'merged with bgp_peer plugin.\n'
' NOTE: to use this plugin you must also install my '
'"bgp_peer" plugin.\n'
'v0.5: merged with bgp_peer '
'(https://thl-cmk.hopto.org/gitlab/checkmk/vendor-independent/bgp_peer)\n',
'download_url': 'https://thl-cmk.hopto.org',
'files': {'agent_based': ['cisco_bgp_peer.py'],
'checkman': ['cisco_bgp_peer'],
'web': ['plugins/wato/cisco_bgp_peer.py',
'plugins/metrics/cisco_bgp_peer.py']},
'checkman': ['cisco_bgp_peer']},
'name': 'cisco_bgp_peer',
'num_files': 4,
'num_files': 2,
'title': 'Cisco BGP Peer',
'version': '20210823.v.0.3e',
'version': '20211114.v.0.5',
'version.min_required': '2.0.0',
'version.packaged': '2021.07.14',
'version.packaged': '2021.09.20',
'version.usable_until': None}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment