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 8af06035 authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

update project

parent 357bf6dc
No related branches found
No related tags found
No related merge requests found
......@@ -28,8 +28,10 @@
# 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)
#
# ToDo: make check/discovery function the base for huawei_bgp_peer
# Example Agent Output:
# BGP4-MIB
......@@ -85,9 +87,20 @@ def parse_bgp_peer(string_table: StringTable) -> Optional[Dict[str, BgpPeer]]:
return peer_table
def discovery_bgp_peer(section: Dict[str, BgpPeer]) -> DiscoveryResult:
def discovery_bgp_peer(params, section: Dict[str, BgpPeer]) -> DiscoveryResult:
_item_parts = [
'remote_address',
'address_family',
'routing_instance',
]
for key in section.keys():
yield Service(item=key)
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 check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult:
......@@ -101,6 +114,8 @@ def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult:
'6': 0, # established
}
item = params.get('internal_item', item)
neighborstate.update(params.get('neighborstate', neighborstate)) # update neighbor status with params
peer_not_found_state = params['peernotfound']
......@@ -135,26 +150,27 @@ def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult:
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}')
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
elif acceptedprefixes is not None:
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.',
notice='Prefix limit/warn threshold not configured on the device.',
)
warnthreshold = None
if peer.admin_state == 2: # no perfdata if admin shutdown
if acceptedprefixes is not None:
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=(warnthreshold, prefixadminlimit),
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}'
)
......@@ -200,6 +216,14 @@ register.check_plugin(
name='bgp_peer',
service_name='BGP peer %s',
discovery_function=discovery_bgp_peer,
discovery_default_parameters={
'build_item': [
# 'remote_address',
# 'address_family',
# 'routing_instance',
]
},
discovery_ruleset_name='discovery_bgp_peer',
check_function=check_bgp_peer,
check_default_parameters={
'minuptime': (7200, 3600),
......
......@@ -9,27 +9,33 @@
#
# inventory of bgp peers
#
# 2022-04-30: code cleanup/streamlining
#
import time
from typing import List
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
register,
SNMPTree,
TableRow,
exists,
OIDBytes
)
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
StringTable,
StringByteTable,
InventoryResult,
)
from cmk.base.plugins.agent_based.utils.bgp_peer import (
ByteToHex,
bgp_errors,
bgp_error_code_as_hex,
bgp_error_as_string,
InvBgpPeer,
get_bgp_type,
BgpWhois,
)
def parse_inv_bgp_peer(string_table: List[StringTable]):
def parse_inv_bgp_peer(string_table: List[StringByteTable]):
peers, base = string_table
try:
local_as, local_id = base[0]
......@@ -41,11 +47,11 @@ def parse_inv_bgp_peer(string_table: List[StringTable]):
for entry in peers:
try:
remote_id, version, local_addr, remote_addr, remote_as, last_error = entry
remote_id, state, version, local_addr, remote_addr, remote_as, last_error, fsm_established_time = entry
except ValueError:
return
bgp_peers.append({
bgp_peer: InvBgpPeer = {
'remote_addr': remote_addr,
'remote_id': remote_id,
'version': version,
......@@ -53,20 +59,30 @@ def parse_inv_bgp_peer(string_table: List[StringTable]):
'remote_as': remote_as,
'local_as': local_as,
'local_id': local_id,
'bgp_type': 'iBGP' if local_as == remote_as else 'eBGP',
'status_columns': {
'last_error_code': ByteToHex(last_error),
'last_error': bgp_errors(last_error),
},
})
'bgp_type': get_bgp_type(local_as, remote_as),
'fsm_established_time': int(fsm_established_time),
'peer_state': 1 if state == '6' else 2, # adjust to match if_oper_status for inventory painter
'last_error_code': bgp_error_code_as_hex(last_error),
'last_error': bgp_error_as_string(last_error),
'status_columns': {},
'address_family': 'N/A'
}
bgp_peers.append(bgp_peer)
return bgp_peers
def inventory_bgp_peers(params, section) -> InventoryResult:
path = ['networking', 'bgp_peers']
whois = None
if params.get('whois_enable'):
whois = BgpWhois(
default_rir=params['whois_enable'].get('whois_rir', 'https://rdap.db.ripe.net'),
timeout=params['whois_enable'].get('whois_timeout', 5)
)
for bgp_peer in section:
key_columns = {'remote_addr': bgp_peer['remote_addr']}
for key in key_columns.keys():
......@@ -75,6 +91,29 @@ def inventory_bgp_peers(params, section) -> InventoryResult:
status_columns = bgp_peer['status_columns']
bgp_peer.pop('status_columns')
if whois:
as_info = whois.get_whois_data_by_asn(int(bgp_peer.get('remote_as')))
bgp_peer.update(as_info)
for column in params.get('remove_columns', []):
try:
bgp_peer.pop(column)
except KeyError:
pass
fsm_established_time = bgp_peer.get('fsm_established_time')
if fsm_established_time:
bgp_peer.pop('fsm_established_time')
peer_state = bgp_peer.get('peer_state')
in_service = True
not_in_service_time = params.get('not_in_service_time', 2592000)
if peer_state == 2: # not established
if fsm_established_time >= not_in_service_time:
in_service = False
bgp_peer.update({'in_service': in_service})
bgp_peer.update({'last_change': time.time() - fsm_established_time})
yield TableRow(
path=path,
key_columns=key_columns,
......@@ -82,6 +121,9 @@ def inventory_bgp_peers(params, section) -> InventoryResult:
status_columns=status_columns
)
if whois:
del whois
register.snmp_section(
name='inv_bgp_peer',
......@@ -91,11 +133,13 @@ register.snmp_section(
base='.1.3.6.1.2.1.15.3.1', # BGP4-MIB::BgpPeerEntry
oids=[
'1', # bgpPeerIdentifier
'2', # bgpPeerState
'4', # bgpPeerNegotiatedVersion
'5', # bgpPeerLocalAddr
'7', # bgpPeerRemoteAddr
'9', # bgpPeerRemoteAs
'14', # bgpPeerLastError
OIDBytes('14'), # bgpPeerLastError
'16', # bgpPeerFsmEstablishedTime
]
),
SNMPTree(
......@@ -113,6 +157,7 @@ register.inventory_plugin(
name='inv_bgp_peer',
inventory_function=inventory_bgp_peers,
inventory_default_parameters={
'not_in_service_time': 2592000, # 30 days in seconds
},
inventory_ruleset_name='inv_bgp_peer',
)
......@@ -7,16 +7,27 @@
# URL : https://thl-cmk.hopto.org
# Date : 2021-08-29
#
# include file, will be used with bgp_peer, inv_bgp_peer, cisco_bgp_peer, inv_cisco_bgp_peer
# include file, will be used with (inv_)bgp_peer, (inv_)cisco_bgp_peer, (inv_)juniper_bgp_peer, huawei_bgp_peer
#
# 2022-04-17: added peer_unavail_reason/peer_unavail_reason_str for huawei bgp peers
# 2022-04-29: added device_admin_limit
# 2022-04-30: code cleanup/streamlining
# 2022-05-09: added item to BgpPeer class, this is used in the discovery function
#
import requests
import json
import re
from typing import List, Tuple, Optional, Dict
import ipaddress
from typing import List, Tuple, Optional, Dict, TypedDict
from dataclasses import dataclass
class BgpPeerItem(TypedDict):
remote_address: str
address_family: str
routing_instance: str
@dataclass
class BgpPeer:
peer_state: int
......@@ -26,6 +37,8 @@ class BgpPeer:
fsm_established_time: int
metric_rate: List[Tuple[str, int]]
metric_count: List[Tuple[str, int]]
item: BgpPeerItem
device_admin_limit: Optional[bool]
prefix_admin_limit: Optional[int]
prefix_threshold: Optional[int]
prefix_clear_threshold: Optional[int]
......@@ -34,6 +47,23 @@ class BgpPeer:
peer_unavail_reason_str: Optional[str]
class InvBgpPeer(TypedDict):
remote_addr: str
remote_id: str
version: str
local_addr:str
remote_as: str
local_as: str
local_id: str
bgp_type: str
fsm_established_time: int
peer_state: int
last_error_code: str
last_error: str
status_columns: Dict[str, str]
address_family: Optional[str]
def sec2hr(seconds):
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
......@@ -65,13 +95,24 @@ def bgp_adminstate(st):
return names.get(st, st)
def ByteToHex(byteStr):
return ''.join(['%02X ' % ord(x) for x in byteStr]).strip()
def get_bgp_type(local_as: str, remote_as: str) -> str:
bgp_type = 'N/A'
if local_as.isdigit() and remote_as.isdigit():
if local_as == remote_as:
bgp_type = 'iBGP'
else:
bgp_type = 'eBGP'
return bgp_type
def bgp_errors(bytestring):
byte1, byte2 = ByteToHex(bytestring).split()
def bgp_error_code_as_hex(error_code: List[int]):
return ''.join([f'{m:02x}' for m in error_code])
def bgp_error_as_string(error_code: List[int]):
# byte1, byte2 = ByteToHex(bytestring).split()
main_code, sub_code = error_code
names = {}
names[0] = {0: 'NO ERROR'}
names[1] = {
......@@ -115,14 +156,10 @@ def bgp_errors(bytestring):
4: 'Connection Rejected',
5: 'Other Configuration Change',
}
return names[int(byte1, 16)].get(int(byte2, 16))
return names[main_code].get(sub_code)
def bgp_render_ipv4_address(bytestring):
return '.'.join([f'{ord(m)}' for m in bytestring])
def bgp_shorten_ipv6_adress(address):
def bgp_shorten_ipv6_address(address):
address = address.split(':')
span = 2
address = [''.join(address[i:i + span]) for i in range(0, len(address), span)]
......@@ -139,35 +176,38 @@ def bgp_shorten_ipv6_adress(address):
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)
def bgp_render_ip_address(addr_type: str, addr: List[int]) -> str:
if addr_type == '1':
return '.'.join([str(m) for m in addr])
elif addr_type == '2':
# IPv6 address from snmp oid in decimal
# [10, 1, 7, 40, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 5, 25]
# change to hex with leading zero
# ['0a', '01', '07', '28', '00', '00', '32', '00', '00', '00', '00', '00', '00', '00', '05', '19']
remote_address = ':'.join([f'{m:02x}' for m in addr]).split(':')
# convert to long ipv6 address 0a01:0728:0000:3200:0000:0000:0000:0519
remote_address = ':'.join([''.join(remote_address[i:i + 2]) for i in range(0, len(remote_address), 2)])
# convert to short ipv6 address a01:728:0:3200::519
remote_address = str(ipaddress.ip_address(remote_address))
# replace bytes in entry with ip address
return remote_address
else:
return ''
return 'N/A'
def bgp_get_peer(OID_END):
def bgp_get_ip_address_from_oid(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)
# u'2.16.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
ip_address = ''
oid_end = oid_end.split('.')
if int(oid_end[1]) == 4: # length of ip address
ip_address = '.'.join(oid_end[2:6]) # ipv4 address
elif int(oid_end[1]) == 16: # ipv6 address
ip_address = ':'.join('%02s' % hex(int(m))[2:] for m in oid_end[2:18]).replace(' ', '0').upper()
ip_address = bgp_shorten_ipv6_address(ip_address)
return peer_ip
return ip_address
def bgp_get_peer_entry(peer: List) -> Optional[Dict[str, BgpPeer]]:
......@@ -185,6 +225,12 @@ def bgp_get_peer_entry(peer: List) -> Optional[Dict[str, BgpPeer]]:
fsm_established_time=int(fsm_established_time),
metric_count=[],
metric_rate=[],
item={
'remote_address': remote_addr,
'address_family': '',
'routing_instance': '',
},
device_admin_limit=None,
prefix_admin_limit=None,
prefix_threshold=None,
prefix_clear_threshold=None,
......@@ -214,3 +260,246 @@ def bgp_get_peer_entry(peer: List) -> Optional[Dict[str, BgpPeer]]:
pass
return {remote_addr: bgp_peer}
def _fetch_data(url: str, timeout: int) -> dict:
response = requests.get(
url=url,
timeout=timeout,
)
# ToDo: improve/Implement error handling
if response.status_code == 200:
return json.loads(response.text)
else:
return {}
class BgpWhois:
__rdap_boot_strap = {
'source': 'https://data.iana.org/rdap/asn.json',
'description': 'RDAP bootstrap file for Autonomous System Number allocations',
'publication': '2021-12-07T20:00:01Z',
'services': [
[
[
'36864-37887',
'327680-328703',
'328704-329727'
],
[
'https://rdap.afrinic.net/rdap/',
'http://rdap.afrinic.net/rdap/'
]
],
[
[
'4608-4865',
'7467-7722',
'9216-10239',
'17408-18431',
'23552-24575',
'37888-38911',
'45056-46079',
'55296-56319',
'58368-59391',
'63488-63999',
'64000-64098',
'64297-64395',
'131072-132095',
'132096-133119',
'133120-133631',
'133632-134556',
'134557-135580',
'135581-136505',
'136506-137529',
'137530-138553',
'138554-139577',
'139578-140601',
'140602-141625',
'141626-142649',
'142650-143673',
'143674-144697',
'144698-145721',
'145722-146745',
'146746-147769',
'147770-148793',
'148794-149817',
'149818-150841',
'150842-151865'
],
[
'https://rdap.apnic.net/'
]
],
[
[
'1-1876',
'1902-2042',
'2044-2046',
'2048-2106',
'2137-2584',
'2615-2772',
'2823-2829',
'2880-3153',
'3354-4607',
'4866-5376',
'5632-6655',
'6912-7466',
'7723-8191',
'10240-12287',
'13312-15359',
'16384-17407',
'18432-20479',
'21504-23455',
'23457-23551',
'25600-26623',
'26624-27647',
'29696-30719',
'31744-32767',
'32768-33791',
'35840-36863',
'39936-40959',
'46080-47103',
'53248-54271',
'54272-55295',
'62464-63487',
'64198-64296',
'393216-394239',
'394240-395164',
'395165-396188',
'396189-397212',
'397213-398236',
'398237-399260',
'399261-400284',
'400285-401308'
],
[
'https://rdap.arin.net/registry/',
'http://rdap.arin.net/registry/'
]
],
[
[
'1877-1901',
'2043',
'2047',
'2107-2136',
'2585-2614',
'2773-2822',
'2830-2879',
'3154-3353',
'5377-5631',
'6656-6911',
'8192-9215',
'12288-13311',
'15360-16383',
'20480-21503',
'24576-25599',
'28672-29695',
'30720-31743',
'33792-34815',
'34816-35839',
'38912-39935',
'40960-41983',
'41984-43007',
'43008-44031',
'44032-45055',
'47104-48127',
'48128-49151',
'49152-50175',
'50176-51199',
'51200-52223',
'56320-57343',
'57344-58367',
'59392-60415',
'60416-61439',
'61952-62463',
'64396-64495',
'196608-197631',
'197632-198655',
'198656-199679',
'199680-200191',
'200192-201215',
'201216-202239',
'202240-203263',
'203264-204287',
'204288-205211',
'205212-206235',
'206236-207259',
'207260-208283',
'208284-209307',
'209308-210331',
'210332-211355',
'211356-212379',
'212380-213403'
],
[
'https://rdap.db.ripe.net/'
]
],
[
[
'27648-28671',
'52224-53247',
'61440-61951',
'64099-64197',
'262144-263167',
'263168-263679',
'263680-264604',
'264605-265628',
'265629-266652',
'266653-267676',
'267677-268700',
'268701-269724',
'269725-270748',
'270749-271772',
'271773-272796',
'272797-273820'
],
[
'https://rdap.lacnic.net/rdap/'
]
]
],
'version': '1.0'
}
__rirs = {
'ripe': 'https://rdap.db.ripe.net',
'arin': 'https://rdap.arin.net/registry',
'afrinic': 'https://rdap.afrinic.net/rdap',
'lacnic': 'https://rdap.lacnic.net/rdap',
'apnic': 'https://rdap.apnic.net',
}
def __find_rir_by_asn(self, asn: int) -> str:
for rir in self.__rdap_boot_strap['services']:
url = rir[1][0] # https rdap url
for asns in rir[0]:
asns = asns.split('-')
if len(asns) == 1:
asns = asns + asns
if int(asns[0]) <= asn <= int(asns[1]):
return url
return self.__rir
def __init__(self, default_rir: str, timeout: int):
self.__timeout = timeout
self.__rir = self.__rirs.get(default_rir, 'https://rdap.db.ripe.net')
self.__known_asns = {}
def get_whois_data_by_asn(self, asn: int) -> Dict[str, str]:
asn_info = {}
# don't fetch for private ASNs, two byte or four byte ASN number
if asn < 64512 or (65536 < asn < 4200000000):
rir = self.__find_rir_by_asn(asn)
query = 'autnum'
data = _fetch_data(f'{rir}{query}/{asn}', self.__timeout)
if data:
asn_info['as_name'] = data.get('name')
vcard_array = data.get('entities')[0].get('vcardArray')
if vcard_array:
for line in vcard_array[1]:
if line[0] == 'fn':
asn_info['as_org_name'] = line[3]
self.__known_asns.update(asn_info)
return asn_info
No preview for this file type
......@@ -15,11 +15,12 @@
'checkman': ['bgp_peer'],
'web': ['plugins/metrics/bgp_peer.py',
'plugins/views/inv_bgp_peer.py',
'plugins/wato/bgp_peer.py']},
'plugins/wato/bgp_peer.py',
'plugins/wato/inv_bgp_peer.py']},
'name': 'bgp_peer',
'num_files': 7,
'num_files': 8,
'title': 'BGP Peer State Check',
'version': '20220418.v1.7',
'version': '20220509.v1.8',
'version.min_required': '2.0.0',
'version.packaged': '2021.09.20',
'version.usable_until': None}
\ No newline at end of file
......@@ -87,7 +87,27 @@ metric_info['bgp_peer_suppressedprefixes'] = {
'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',
}
######################################################################################################################
......@@ -165,6 +185,17 @@ graph_info['bgp_peer.time_since_last_update'] = {
'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
......
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from cmk.gui.i18n import _
from cmk.gui.plugins.views import (
inventory_displayhints,
)
from cmk.gui.i18n import _
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', 'local_addr', 'remote_id', 'local_id', 'remote_as', 'local_as', 'bgp_type', 'version',
'remote_addr',
'peer_state', 'last_change', 'in_service',
'local_addr', 'remote_id', 'local_id', 'remote_as', 'local_as',
],
'view': 'invbgppeer_of_host',
},
......@@ -25,8 +33,26 @@ inventory_displayhints.update({
'.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,
},
})
from cmk.gui.plugins.views.inventory import declare_invtable_view
declare_invtable_view('invbgppeer', '.networking.bgp_peers:', _('BGP peers'), _('BGP peers'))
......@@ -13,7 +13,10 @@
# 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
#
from cmk.gui.i18n import _
from cmk.gui.valuespec import (
Dictionary,
......@@ -23,12 +26,15 @@ from cmk.gui.valuespec import (
Tuple,
TextUnicode,
MonitoringState,
ListChoice,
)
from cmk.gui.plugins.wato import (
CheckParameterRulespecWithItem,
rulespec_registry,
RulespecGroupCheckParametersNetworking,
HostRulespec,
RulespecGroupCheckParametersDiscovery,
)
......@@ -37,10 +43,30 @@ def _parameter_valuespec_bgp_peer():
('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 if below'), unit='seconds', default_value=7200, minvalue=0),
Integer(title=_('Critical if below'), unit='seconsa', default_value=3600, minvalue=0)
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',
......@@ -136,18 +162,21 @@ def _parameter_valuespec_bgp_peer():
('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,
......@@ -172,3 +201,39 @@ rulespec_registry.register(
parameter_valuespec=_parameter_valuespec_bgp_peer,
title=lambda: _('BGP peer'),
))
def _valuespec_discovery_bgp_peer():
item_parts = [
# ('remote_address', 'Peer remote address'),
('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=[],
)),
],
)
rulespec_registry.register(
HostRulespec(
group=RulespecGroupCheckParametersDiscovery,
match_type='dict',
name='discovery_bgp_peer',
valuespec=_valuespec_discovery_bgp_peer,
))
#!/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 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,
))
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