diff --git a/README.md b/README.md index 9e11d586ccebd030d84cf89bb6c494ab8edf28f6..b3c8c04d2064201703935d7dab6df7a43c1a326e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/bgp_topology-0.0.1-20240722.mkp "bgp_topology-0.0.1-20240722.mkp" +[PACKAGE]: ../../raw/master/mkp/bgp_topology-0.0.2-20241223.mkp "bgp_topology-0.0.2-20241223.mkp" # Title A short description about the plugin diff --git a/mkp/bgp_topology-0.0.2-20241223.mkp b/mkp/bgp_topology-0.0.2-20241223.mkp new file mode 100644 index 0000000000000000000000000000000000000000..aab7e559ec5897b550f05275b7ade84e77783b3a Binary files /dev/null and b/mkp/bgp_topology-0.0.2-20241223.mkp differ diff --git a/source/cmk_addons_plugins/bgp_topology/constants.py b/source/cmk_addons_plugins/bgp_topology/constants.py index 12130842fea6c98ee690dd806891f7ce8ca55f34..98a65eea645a59296b89ab89e883c80a1785eb7b 100644 --- a/source/cmk_addons_plugins/bgp_topology/constants.py +++ b/source/cmk_addons_plugins/bgp_topology/constants.py @@ -10,13 +10,17 @@ # 2024-07-16: copied from bgp_topology/lib/ruleset_names.py +__AUTHOR__ = 'thl-cmk[at]outlook[dot]com' +__URL__ = 'https://thl-cmk.hopto.org/gitlab/checkmk/vendor-independent/bgp_topology' +__USAGE__ = '~/local/lib/python3/cmk_addons/plugins/bgp_topology/libexec/check_bgp_topology --make-default' +__VERSION__ = '0.0.2-20241223' from typing import Final ARG_PARSER_ANCHOR: Final[str] = '--bgp-anchor' -ARG_PARSER_ANCHOR_AS: Final[str] = 'bgp-as' +ARG_PARSER_ANCHOR_AS: Final[str] = 'as' ARG_PARSER_ANCHOR_BOTH: Final[str] = 'both' -ARG_PARSER_ANCHOR_ID: Final[str] = 'bgp-id' +ARG_PARSER_ANCHOR_ID: Final[str] = 'id' ARG_PARSER_EMBLEM_AS: Final[str] = '--bgp-emblem-as' ARG_PARSER_EMBLEM_ID: Final[str] = '--bgp-emblem-id' ARG_PARSER_HOST: Final[str] = '--host' @@ -24,6 +28,7 @@ ARG_PARSER_MAKE_DEFAULT: Final[str] = '--make-default' ARG_PARSER_NONE: Final[str] = 'none' ARG_PARSER_SITES_EXCLUDE: Final[str] = '--exclude-sites' ARG_PARSER_SITES_INCLUDE: Final[str] = '--include-sites' +ARG_PARSER_DEBUG: Final[str] = '--debug' BGP_PEER_LOCAL_ADDR: Final[str] = 'local_addr' BGP_PEER_LOCAL_AS: Final[str] = 'local_as' diff --git a/source/cmk_addons_plugins/bgp_topology/lib/bgp_topology.py b/source/cmk_addons_plugins/bgp_topology/lib/bgp_topology.py index 76e4d0a1e2d536927c255b938173823de93f3bfd..9b5f42d286eae67a0a6519936f681fa866a2c440 100644 --- a/source/cmk_addons_plugins/bgp_topology/lib/bgp_topology.py +++ b/source/cmk_addons_plugins/bgp_topology/lib/bgp_topology.py @@ -9,30 +9,15 @@ # File : bgp_topology/lib/bgp_topology.py # 2024-07-20: moved to lib -> is now an active check +# 2024-12-23: moved arg parser to lib/args.py +# fixed handling of anchors -__AUTHOR__ = 'thl-cmk[at]outlook[dot]com' -__URL__ = 'https://thl-cmk.hopto.org/gitlab/checkmk/vendor-independent/bgp_topology' -__USAGE__ = '/local/lib/python3/cmk_addons/plugins/bgp_topology/libexec/check_bgp_topology --make-default' -__VERSION__ = '0.0.1-20240721' - -from argparse import ArgumentParser, Namespace, RawTextHelpFormatter from collections.abc import MutableMapping, MutableSequence, Sequence from dataclasses import dataclass from time import time_ns from cmk.agent_based.v2 import render from cmk_addons.plugins.bgp_topology.constants import ( - ARG_PARSER_ANCHOR, - ARG_PARSER_ANCHOR_AS, - ARG_PARSER_ANCHOR_BOTH, - ARG_PARSER_ANCHOR_ID, - ARG_PARSER_EMBLEM_AS, - ARG_PARSER_EMBLEM_ID, - ARG_PARSER_HOST, - ARG_PARSER_MAKE_DEFAULT, - ARG_PARSER_NONE, - ARG_PARSER_SITES_EXCLUDE, - ARG_PARSER_SITES_INCLUDE, BGP_PEER_LOCAL_ADDR, BGP_PEER_LOCAL_AS, BGP_PEER_LOCAL_ID, @@ -41,19 +26,20 @@ from cmk_addons.plugins.bgp_topology.constants import ( BGP_PEER_REMOTE_ID, BGP_PEER_STATE, BGP_PEER_UPTIME, - EMBLEM_BGP_AS, - EMBLEM_BGP_ID, METRIC_TIME_TAKEN, PARAM_BGP_EXT_ANCHOR_AS, PARAM_BGP_EXT_ANCHOR_BOTH, PARAM_BGP_EXT_ANCHOR_ID, TOPOLOGY_NAME, ) +from cmk_addons.plugins.bgp_topology.lib.args import ( + Params, + parse_arguments, +) from cmk_addons.plugins.bgp_topology.lib.utils import ( BASE_TOPO_PATH, LiveStatusConnection, Metric, - OMD_ROOT, TopoConnections, TopoObjects, add_dummy_topologies, @@ -67,16 +53,6 @@ from cmk_addons.plugins.bgp_topology.lib.utils import ( ) -class Params(Namespace): - bgp_anchor: str - make_default: bool = False - bgp_emblem_as: str = EMBLEM_BGP_AS - bgp_emblem_id: str = EMBLEM_BGP_ID - include_sites: Sequence[str] | None = None - exclude_sites: Sequence[str] | None = None - host: str = '' - - @dataclass(frozen=True) class BgpPeer: host: str @@ -104,7 +80,7 @@ class BgpPeer: value = None key: str | None = get_bgp_peer_clean_key(key) value: str | None = get_bgp_peer_clean_value(key, value) - if key is not None and value is not None: + if key is not None and value not in [None, '0.0.0.0']: bgp_peer[key] = value return cls( @@ -122,6 +98,51 @@ class BgpPeer: ) +def add_bgp_anchor( + bgp_anchor : str, + bgp_peer: BgpPeer, + objects: TopoObjects, + connections: TopoConnections, + emblem_as: str, + emblem_id: str, +): + ext_bgp_host_as: str | None = None + ext_bgp_host_id: str | None = None + if bgp_anchor in [ + PARAM_BGP_EXT_ANCHOR_BOTH, + PARAM_BGP_EXT_ANCHOR_AS, + ] and bgp_peer.remote_as is not None: + ext_bgp_host_as: str = f'BGP-AS: {bgp_peer.remote_as}' + objects.add_host( + host=ext_bgp_host_as, + link2core=False, + emblem=emblem_as, + ) + if bgp_anchor in [ + PARAM_BGP_EXT_ANCHOR_BOTH, + PARAM_BGP_EXT_ANCHOR_ID + ] and bgp_peer.remote_id is not None: + ext_bgp_host_id: str = f'BGP-ID: {bgp_peer.remote_id}' + objects.add_host( + host=ext_bgp_host_id, + link2core=False, + emblem=emblem_id + ) + connections.add_connection( + right=ext_bgp_host_id, + left=get_service(bgp_peer.host, bgp_peer.service), + left_state=bgp_peer.state + ) + if ext_bgp_host_as is not None: + connections.add_connection(ext_bgp_host_id, ext_bgp_host_as) + + if ext_bgp_host_as is not None and ext_bgp_host_id is None: + connections.add_connection( + right=get_service(bgp_peer.host, bgp_peer.service), + left=ext_bgp_host_as, + right_state=bgp_peer.state, + ) + def create_bgp_topology(params: Params | None) -> int: start_time = time_ns() @@ -151,10 +172,12 @@ def create_bgp_topology(params: Params | None) -> int: query: str = ( 'GET services\n' 'Columns: host_name state description long_plugin_output\n' - 'Filter: description ~ BGP peer\n' + 'Filter: description ~ BGP [Pp]eer\n' 'OutputFormat: python3\n' ) if (raw_bgp_peers := ls_connection.query(query=query)) is not None: + if params.debug: + print(raw_bgp_peers) bgp_peers: MutableSequence[BgpPeer] = [ BgpPeer.parse(host, state, service, raw_peer_data) for host, state, service, raw_peer_data in raw_bgp_peers ] @@ -170,18 +193,19 @@ def create_bgp_topology(params: Params | None) -> int: left_state=bgp_peer.state ) - if bgp_peer.local_address is not None: + if bgp_peer.local_address not in [None]: if bgp_peers_by_local_addr.get(bgp_peer.local_address) is None: bgp_peers_by_local_addr[bgp_peer.local_address]: MutableSequence[BgpPeer] = [] bgp_peers_by_local_addr[bgp_peer.local_address].append(bgp_peer) else: - bgp_peers_by_local_addr['0.0.0.0'].append(bgp_peer) + bgp_peers_by_local_addr['0.0.0.0'].append(bgp_peer) # find connections for bgp_peer in bgp_peers: if (peer_list := bgp_peers_by_local_addr.get(bgp_peer.remote_address)) is not None: for peer in peer_list: - if bgp_peer.local_as == peer.remote_as and bgp_peer.local_as is not None: + # local_as is not available in the built-in plugins + # if bgp_peer.local_as == peer.remote_as and bgp_peer.local_as is not None: if bgp_peer.local_id == peer.remote_id and bgp_peer.local_id is not None: if bgp_peer.local_address == peer.remote_address and bgp_peer.local_address is not None: connections.add_connection( @@ -194,42 +218,24 @@ def create_bgp_topology(params: Params | None) -> int: # if there is no peer_list the peer is either external (to checkmk) or the connection is not # established, so we have no local address or remote id else: - ext_bgp_host_as: str | None = None - ext_bgp_host_id: str | None = None - if bgp_anchor in [ - PARAM_BGP_EXT_ANCHOR_BOTH, - PARAM_BGP_EXT_ANCHOR_AS, - ] and bgp_peer.remote_as is not None: - ext_bgp_host_as: str = f'BGP-AS: {bgp_peer.remote_as}' - objects.add_host( - host=ext_bgp_host_as, - link2core=False, - emblem=emblem_as, - ) - if bgp_anchor in [ - PARAM_BGP_EXT_ANCHOR_BOTH, - PARAM_BGP_EXT_ANCHOR_ID - ] and bgp_peer.remote_id is not None: - ext_bgp_host_id: str = f'BGP-ID: {bgp_peer.remote_id}' - objects.add_host( - host=ext_bgp_host_id, - link2core=False, - emblem=emblem_id - ) - connections.add_connection( - right=ext_bgp_host_id, - left=get_service(bgp_peer.host, bgp_peer.service), - left_state=bgp_peer.state - ) - if ext_bgp_host_as is not None: - connections.add_connection(ext_bgp_host_id, ext_bgp_host_as) - - if ext_bgp_host_as is not None and ext_bgp_host_id is None: - connections.add_connection( - right=get_service(bgp_peer.host, bgp_peer.service), - left=ext_bgp_host_as, - right_state=bgp_peer.state, - ) + add_bgp_anchor( + bgp_anchor=bgp_anchor, + bgp_peer=bgp_peer, + objects=objects, + connections=connections, + emblem_as=emblem_as, + emblem_id=emblem_id, + ) + + for bgp_peer in bgp_peers_by_local_addr['0.0.0.0']: + add_bgp_anchor( + bgp_anchor=bgp_anchor, + bgp_peer=bgp_peer, + objects=objects, + connections=connections, + emblem_as=emblem_as, + emblem_id=emblem_id, + ) connections.topo_connections.sort() data_set = { @@ -270,75 +276,6 @@ def create_bgp_topology(params: Params | None) -> int: return 0 -def parse_arguments(argv: Sequence[str]) -> Params: - parser = ArgumentParser( - prog='bgp_topology', - formatter_class=RawTextHelpFormatter, - description=f"""Create BGP peer network topology for Checkmk""", - epilog=f""" -Example usage: -{OMD_ROOT}/{__USAGE__} - -Version: {__VERSION__} | Written by {__AUTHOR__} -for more information see: {__URL__} - """ - ) - parser.add_argument( - ARG_PARSER_ANCHOR, - choices=[ - ARG_PARSER_ANCHOR_BOTH, - ARG_PARSER_ANCHOR_AS, - ARG_PARSER_ANCHOR_ID, - ARG_PARSER_NONE, - ], - default=ARG_PARSER_ANCHOR_BOTH, - help='Anchor for external BGP objects (default: %(default)s).', - ) - parser.add_argument( - ARG_PARSER_EMBLEM_AS, - type=str, - default=EMBLEM_BGP_AS, - help='Emblem to use for BGP-AS objects (default: %(default)s).', - ) - parser.add_argument( - ARG_PARSER_EMBLEM_ID, - type=str, - default=EMBLEM_BGP_ID, - help='Emblem to use for BGP-ID objects (default: %(default)s).', - ) - parser.add_argument( - ARG_PARSER_MAKE_DEFAULT, - action='store_const', const=True, - default=False, - help='Make this topology the default (default: %(default)s).', - ) - parser.add_argument( - ARG_PARSER_HOST, - type=str, - help="""The name of the Checkmk host to which the plugin is attached. This is set -automatically by Checkmk. If a site filter is active, the host name is -appended to the subdirectory where the topology is stored (“BGP†becomes -“BGP_host_nameâ€). This way we can have more than one BGP topology without -overwriting each other.""", - ) - site_filter = parser.add_mutually_exclusive_group() - site_filter.add_argument( - ARG_PARSER_SITES_INCLUDE, - type=str, - nargs='+', - help=f"""List of Checkmk site names to include in the topology creation. -Can not used together with {ARG_PARSER_SITES_EXCLUDE}""", - ) - site_filter.add_argument( - ARG_PARSER_SITES_EXCLUDE, - type=str, - nargs='+', - help=f"""List of Checkmk site names to exclude from the topology creation. -Can not used together with {ARG_PARSER_SITES_INCLUDE}""", - ) - - return parser.parse_args(argv) - def main(argv: Sequence[str] | None = None) -> int: return create_bgp_topology(parse_arguments(argv=argv)) diff --git a/source/cmk_addons_plugins/bgp_topology/server_side_calls/bgp_topology.py b/source/cmk_addons_plugins/bgp_topology/server_side_calls/bgp_topology.py index 37baa8ea2c21b0148354a7bec7d4de3ecb390e11..e0230072d4fcb4a3a7395544084e21eb54ca7cf1 100644 --- a/source/cmk_addons_plugins/bgp_topology/server_side_calls/bgp_topology.py +++ b/source/cmk_addons_plugins/bgp_topology/server_side_calls/bgp_topology.py @@ -56,6 +56,7 @@ FILTER_SITES = ( tuple[Literal['include_sites'], Sequence[str]] ) + class BgpAnchorType: anchor_both: str = PARAM_BGP_EXT_ANCHOR_BOTH anchor_as: str = PARAM_BGP_EXT_ANCHOR_AS diff --git a/source/packages/bgp_topology b/source/packages/bgp_topology index 7ebfba5d80128a72d9401f749c6656dc87485ae7..acc7bf882037e97a7b03ddeb082c640ae4677a07 100644 --- a/source/packages/bgp_topology +++ b/source/packages/bgp_topology @@ -10,7 +10,7 @@ 'bgp_topology/graphing/bgp_topology.py']}, 'name': 'bgp_topology', 'title': 'BGP peer topology', - 'version': '0.0.1-20240722', + 'version': '0.0.2-20241223', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.usable_until': '2.4.0b1'}