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

fixed handling of anchors

parent 8b7a2243
No related branches found
No related tags found
No related merge requests found
[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 # Title
A short description about the plugin A short description about the plugin
......
File added
...@@ -10,13 +10,17 @@ ...@@ -10,13 +10,17 @@
# 2024-07-16: copied from bgp_topology/lib/ruleset_names.py # 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 from typing import Final
ARG_PARSER_ANCHOR: Final[str] = '--bgp-anchor' 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_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_AS: Final[str] = '--bgp-emblem-as'
ARG_PARSER_EMBLEM_ID: Final[str] = '--bgp-emblem-id' ARG_PARSER_EMBLEM_ID: Final[str] = '--bgp-emblem-id'
ARG_PARSER_HOST: Final[str] = '--host' ARG_PARSER_HOST: Final[str] = '--host'
...@@ -24,6 +28,7 @@ ARG_PARSER_MAKE_DEFAULT: Final[str] = '--make-default' ...@@ -24,6 +28,7 @@ ARG_PARSER_MAKE_DEFAULT: Final[str] = '--make-default'
ARG_PARSER_NONE: Final[str] = 'none' ARG_PARSER_NONE: Final[str] = 'none'
ARG_PARSER_SITES_EXCLUDE: Final[str] = '--exclude-sites' ARG_PARSER_SITES_EXCLUDE: Final[str] = '--exclude-sites'
ARG_PARSER_SITES_INCLUDE: Final[str] = '--include-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_ADDR: Final[str] = 'local_addr'
BGP_PEER_LOCAL_AS: Final[str] = 'local_as' BGP_PEER_LOCAL_AS: Final[str] = 'local_as'
......
...@@ -9,30 +9,15 @@ ...@@ -9,30 +9,15 @@
# File : bgp_topology/lib/bgp_topology.py # File : bgp_topology/lib/bgp_topology.py
# 2024-07-20: moved to lib -> is now an active check # 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 collections.abc import MutableMapping, MutableSequence, Sequence
from dataclasses import dataclass from dataclasses import dataclass
from time import time_ns from time import time_ns
from cmk.agent_based.v2 import render from cmk.agent_based.v2 import render
from cmk_addons.plugins.bgp_topology.constants import ( 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_ADDR,
BGP_PEER_LOCAL_AS, BGP_PEER_LOCAL_AS,
BGP_PEER_LOCAL_ID, BGP_PEER_LOCAL_ID,
...@@ -41,19 +26,20 @@ from cmk_addons.plugins.bgp_topology.constants import ( ...@@ -41,19 +26,20 @@ from cmk_addons.plugins.bgp_topology.constants import (
BGP_PEER_REMOTE_ID, BGP_PEER_REMOTE_ID,
BGP_PEER_STATE, BGP_PEER_STATE,
BGP_PEER_UPTIME, BGP_PEER_UPTIME,
EMBLEM_BGP_AS,
EMBLEM_BGP_ID,
METRIC_TIME_TAKEN, METRIC_TIME_TAKEN,
PARAM_BGP_EXT_ANCHOR_AS, PARAM_BGP_EXT_ANCHOR_AS,
PARAM_BGP_EXT_ANCHOR_BOTH, PARAM_BGP_EXT_ANCHOR_BOTH,
PARAM_BGP_EXT_ANCHOR_ID, PARAM_BGP_EXT_ANCHOR_ID,
TOPOLOGY_NAME, TOPOLOGY_NAME,
) )
from cmk_addons.plugins.bgp_topology.lib.args import (
Params,
parse_arguments,
)
from cmk_addons.plugins.bgp_topology.lib.utils import ( from cmk_addons.plugins.bgp_topology.lib.utils import (
BASE_TOPO_PATH, BASE_TOPO_PATH,
LiveStatusConnection, LiveStatusConnection,
Metric, Metric,
OMD_ROOT,
TopoConnections, TopoConnections,
TopoObjects, TopoObjects,
add_dummy_topologies, add_dummy_topologies,
...@@ -67,16 +53,6 @@ from cmk_addons.plugins.bgp_topology.lib.utils import ( ...@@ -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) @dataclass(frozen=True)
class BgpPeer: class BgpPeer:
host: str host: str
...@@ -104,7 +80,7 @@ class BgpPeer: ...@@ -104,7 +80,7 @@ class BgpPeer:
value = None value = None
key: str | None = get_bgp_peer_clean_key(key) key: str | None = get_bgp_peer_clean_key(key)
value: str | None = get_bgp_peer_clean_value(key, value) 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 bgp_peer[key] = value
return cls( return cls(
...@@ -122,6 +98,51 @@ class BgpPeer: ...@@ -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: def create_bgp_topology(params: Params | None) -> int:
start_time = time_ns() start_time = time_ns()
...@@ -151,10 +172,12 @@ def create_bgp_topology(params: Params | None) -> int: ...@@ -151,10 +172,12 @@ def create_bgp_topology(params: Params | None) -> int:
query: str = ( query: str = (
'GET services\n' 'GET services\n'
'Columns: host_name state description long_plugin_output\n' 'Columns: host_name state description long_plugin_output\n'
'Filter: description ~ BGP peer\n' 'Filter: description ~ BGP [Pp]eer\n'
'OutputFormat: python3\n' 'OutputFormat: python3\n'
) )
if (raw_bgp_peers := ls_connection.query(query=query)) is not None: if (raw_bgp_peers := ls_connection.query(query=query)) is not None:
if params.debug:
print(raw_bgp_peers)
bgp_peers: MutableSequence[BgpPeer] = [ bgp_peers: MutableSequence[BgpPeer] = [
BgpPeer.parse(host, state, service, raw_peer_data) for host, state, service, raw_peer_data in raw_bgp_peers 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: ...@@ -170,18 +193,19 @@ def create_bgp_topology(params: Params | None) -> int:
left_state=bgp_peer.state 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: 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]: MutableSequence[BgpPeer] = []
bgp_peers_by_local_addr[bgp_peer.local_address].append(bgp_peer) bgp_peers_by_local_addr[bgp_peer.local_address].append(bgp_peer)
else: 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 # find connections
for bgp_peer in bgp_peers: for bgp_peer in bgp_peers:
if (peer_list := bgp_peers_by_local_addr.get(bgp_peer.remote_address)) is not None: if (peer_list := bgp_peers_by_local_addr.get(bgp_peer.remote_address)) is not None:
for peer in peer_list: 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_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: if bgp_peer.local_address == peer.remote_address and bgp_peer.local_address is not None:
connections.add_connection( connections.add_connection(
...@@ -194,42 +218,24 @@ def create_bgp_topology(params: Params | None) -> int: ...@@ -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 # 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 # established, so we have no local address or remote id
else: else:
ext_bgp_host_as: str | None = None add_bgp_anchor(
ext_bgp_host_id: str | None = None bgp_anchor=bgp_anchor,
if bgp_anchor in [ bgp_peer=bgp_peer,
PARAM_BGP_EXT_ANCHOR_BOTH, objects=objects,
PARAM_BGP_EXT_ANCHOR_AS, connections=connections,
] and bgp_peer.remote_as is not None: emblem_as=emblem_as,
ext_bgp_host_as: str = f'BGP-AS: {bgp_peer.remote_as}' emblem_id=emblem_id,
objects.add_host( )
host=ext_bgp_host_as,
link2core=False, for bgp_peer in bgp_peers_by_local_addr['0.0.0.0']:
emblem=emblem_as, add_bgp_anchor(
) bgp_anchor=bgp_anchor,
if bgp_anchor in [ bgp_peer=bgp_peer,
PARAM_BGP_EXT_ANCHOR_BOTH, objects=objects,
PARAM_BGP_EXT_ANCHOR_ID connections=connections,
] and bgp_peer.remote_id is not None: emblem_as=emblem_as,
ext_bgp_host_id: str = f'BGP-ID: {bgp_peer.remote_id}' emblem_id=emblem_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,
)
connections.topo_connections.sort() connections.topo_connections.sort()
data_set = { data_set = {
...@@ -270,75 +276,6 @@ def create_bgp_topology(params: Params | None) -> int: ...@@ -270,75 +276,6 @@ def create_bgp_topology(params: Params | None) -> int:
return 0 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: def main(argv: Sequence[str] | None = None) -> int:
return create_bgp_topology(parse_arguments(argv=argv)) return create_bgp_topology(parse_arguments(argv=argv))
...@@ -56,6 +56,7 @@ FILTER_SITES = ( ...@@ -56,6 +56,7 @@ FILTER_SITES = (
tuple[Literal['include_sites'], Sequence[str]] tuple[Literal['include_sites'], Sequence[str]]
) )
class BgpAnchorType: class BgpAnchorType:
anchor_both: str = PARAM_BGP_EXT_ANCHOR_BOTH anchor_both: str = PARAM_BGP_EXT_ANCHOR_BOTH
anchor_as: str = PARAM_BGP_EXT_ANCHOR_AS anchor_as: str = PARAM_BGP_EXT_ANCHOR_AS
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
'bgp_topology/graphing/bgp_topology.py']}, 'bgp_topology/graphing/bgp_topology.py']},
'name': 'bgp_topology', 'name': 'bgp_topology',
'title': 'BGP peer topology', 'title': 'BGP peer topology',
'version': '0.0.1-20240722', 'version': '0.0.2-20241223',
'version.min_required': '2.3.0b1', 'version.min_required': '2.3.0b1',
'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.packaged': 'cmk-mkp-tool 0.2.0',
'version.usable_until': '2.4.0b1'} 'version.usable_until': '2.4.0b1'}
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