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

update project

parent aa5cbb7b
No related branches found
No related tags found
No related merge requests found
[PACKAGE]: ../../raw/master/create_topology_data-0.0.7-20231019.mkp "create_topology_data-0.0.7-20231019.mkp"
[PACKAGE]: ../../raw/master/create_topology_data-0.0.8-20231020.mkp "create_topology_data-0.0.8-20231020.mkp"
# PoC for Network Visualization data creation from inventory data
This script creates the topology data file needed for the [Checkmk Exchange Network visualization](https://forum.checkmk.com/u/schnetz) plugin by Andreas Boesl and [schnetz](https://exchange.checkmk.com/u/schnetz).\
......
......@@ -12,7 +12,28 @@
from os import environ
from time import strftime
from typing import Dict, List, Any, NamedTuple
from create_topology_utils import lldp_path, lldp_columns, lldp_label, user_data_file
from enum import Enum, unique
from create_topology_utils import (
cdp_path,
cdp_columns,
cdp_label,
lldp_path,
lldp_columns,
lldp_label,
user_data_file,
)
class TopologyParams(NamedTuple):
path: str
columns: str
label: str
@unique
class Topologies(Enum):
CDP = TopologyParams(path=cdp_path, columns=cdp_columns, label=cdp_label)
LLDP = TopologyParams(path=lldp_path, columns=lldp_columns, label=lldp_label)
class InventoryColumns(NamedTuple):
......@@ -51,13 +72,14 @@ class Settings:
self.__settings = {
'seed_devices': None,
'path_in_inventory': 'networking,cdp_cache',
'inventory_columns': 'device_id,local_port,device_port',
'data_source': 'inv_CDP',
'path_in_inventory': cdp_path,
'inventory_columns': cdp_columns,
'data_source': cdp_label,
'time_format': '%Y-%m-%dT%H:%M:%S.%m',
'user_data_file': f'{self.__omd_root}/local/bin/topology_data/{user_data_file}',
'merge': None,
'output_directory': None,
'make_default': False,
'default': False,
'keep_domain': False,
'lowercase': False,
'uppercase': False,
......@@ -79,11 +101,29 @@ class Settings:
self.__settings['inventory_columns'] = lldp_columns
# Then update values with cli values
self.__settings.update(self.__args)
if not self.merge:
if not self.lldp:
self.merge = ['CDP']
else:
self.merge = ['LLDP']
def set_topology_param(self, topology: TopologyParams):
self.__settings['path_in_inventory'] = topology.path
self.__settings['inventory_columns'] = topology.columns
self.__settings['data_source'] = topology.label
@property
def version(self) -> bool:
return self.__settings['version']
@property
def merge(self) -> List[str] | None:
return self.__settings['merge']
@merge.setter
def merge(self, topologies: List[str]):
self.__settings['merge'] = topologies
@property
def keep(self) -> int | None:
if self.__settings['keep']:
......@@ -113,8 +153,8 @@ class Settings:
return self.__settings['dont_compare']
@property
def make_default(self) -> bool:
return self.__settings['make_default']
def default(self) -> bool:
return self.__settings['default']
@property
def keep_domain(self) -> bool:
......
......@@ -21,6 +21,8 @@
# get interfaces from autochecks changed to live status query
# 2023-10-19: cleanup removed "all" unused functions
# added option -u, --user-data-file to provide a user specific data file
# 2023-10-20: changed option -m/--make-default to -d/--default (-m is needed for -m/--merge
# added -m/--merge option
#
# PoC for creating topology_data.json from inventory data
......@@ -63,15 +65,17 @@ from create_topology_utils import (
merge_topologies,
save_topology,
get_data_form_live_status,
ExitCodes,
)
from create_topology_classes import (
InventoryColumns,
Settings,
StaticConnection,
Topologies,
)
CREATE_TOPOLOGY_VERSION = '0.0.7-202310119'
CREATE_TOPOLOGY_VERSION = '0.0.8-202310120'
ITEMS = {}
HOST_MAP: Dict[str, str] = {}
......@@ -293,14 +297,21 @@ def create_topology(
if __name__ == '__main__':
SETTINGS = Settings(vars(parse_arguments(CREATE_TOPOLOGY_VERSION)))
if SETTINGS.version:
print(f'{Path(__file__).name} version: {CREATE_TOPOLOGY_VERSION}')
exit(0)
exit(code=ExitCodes.ok)
if SETTINGS.check_user_data_only:
user_data = get_data_from_toml(file=SETTINGS.user_data_file)
print(f'Could read/parse the user data from {SETTINGS.user_data_file}')
exit(0)
exit(code=ExitCodes.OK)
if SETTINGS.merge:
_merge = list(set(SETTINGS.merge.copy()))
if len(_merge) != len(SETTINGS.merge):
print(f'-m/--merge options must be unique. Use "-m cdp lldp" oder "-m lldp cdp"')
exit(code=ExitCodes.BAD_OPTION_LIST)
print()
print(f'Start time: {strftime(SETTINGS.time_format)}')
......@@ -309,28 +320,33 @@ if __name__ == '__main__':
user_data = get_data_from_toml(file=SETTINGS.user_data_file)
HOST_MAP = user_data.get('HOST_MAP', {})
DROP_HOSTS = user_data.get('DROP_HOSTS', [])
final_topology = {}
while SETTINGS.merge:
SETTINGS.set_topology_param(Topologies[SETTINGS.merge[-1]].value)
topology = create_topology(
seed_devices=list(set(SETTINGS.seed_devices + user_data.get('SEED_DEVICES', []))),
path_in_inventory=SETTINGS.path_in_inventory,
inv_columns=SETTINGS.inventory_columns,
data_source=SETTINGS.data_source,
debug=SETTINGS.debug,
)
if topology:
final_topology = merge_topologies(topo_pri=topology, topo_sec=final_topology)
SETTINGS.merge.remove(SETTINGS.merge[-1])
STATIC_CONNECTIONS = create_static_connections(connections=user_data.get('STATIC_CONNECTIONS', []))
topology = create_topology(
seed_devices=list(set(SETTINGS.seed_devices + user_data.get('SEED_DEVICES', []))),
path_in_inventory=SETTINGS.path_in_inventory,
inv_columns=SETTINGS.inventory_columns,
data_source=SETTINGS.data_source,
debug=SETTINGS.debug,
)
final_topology = merge_topologies(topo_pri=STATIC_CONNECTIONS, topo_sec=final_topology)
if topology:
# merge topology with static connections
topology = merge_topologies(topo_pri=STATIC_CONNECTIONS, topo_sec=topology)
save_topology(
data=topology,
base_directory=f'{SETTINGS.omd_root}/{SETTINGS.topology_save_path}',
output_directory=SETTINGS.output_directory,
topology_file_name=SETTINGS.topology_file_name,
dont_compare=SETTINGS.dont_compare,
make_default=SETTINGS.make_default,
)
save_topology(
data=final_topology,
base_directory=f'{SETTINGS.omd_root}/{SETTINGS.topology_save_path}',
output_directory=SETTINGS.output_directory,
topology_file_name=SETTINGS.topology_file_name,
dont_compare=SETTINGS.dont_compare,
make_default=SETTINGS.default,
)
if SETTINGS.keep:
remove_old_data(
......
......@@ -9,7 +9,7 @@
#
# options used
# -m --make-default
# -d --default
# -o --output-directory
# -s --seed-devices
# -u --user-data-file
......@@ -43,6 +43,15 @@ from argparse import (
ArgumentParser,
RawTextHelpFormatter,
)
from enum import Enum, unique
@unique
class ExitCodes(Enum):
OK = 0
BAD_OPTION_LIST = 1
BAD_TOML_FORMAT = 3
script = '~/local/bin/network-topology/create_topology_data.py'
sample_seeds = 'Core01 Core02'
......@@ -82,7 +91,7 @@ def get_data_from_toml(file: str, debug: bool = False) -> Dict:
except TOMLDecodeError as e:
print(
f'ERROR: data file {toml_file} is not in valid TOML format! ({e}), (see https://toml.io/en/)')
exit(2)
exit(code=ExitCodes.BAD_TOML_FORMAT)
else:
print(f'WARNING: User data {file} not found.')
if debug:
......@@ -325,16 +334,27 @@ def parse_arguments(create_topology_version: str) -> arg_Namespace:
formatter_class=RawTextHelpFormatter,
epilog='Usage:\n'
'for CDP (the default):\n'
f'{script} -s {sample_seeds} -m\n'
f'{script} -s {sample_seeds} -d\n'
'for LLDP:\n'
f'{script} -s {sample_seeds} -m --lldp\n',
f'{script} -s {sample_seeds} -d --lldp\n',
)
command_group = parser.add_mutually_exclusive_group()
parser.add_argument(
'-m', '--make-default', default=False, action='store_const', const=True,
'-d', '--default', default=False, action='store_const', const=True,
help='Set the created topology data as default',
)
parser.add_argument(
'-m', '--merge',
nargs=2,
choices=['CDP', 'LLDP'],
help=f'Merge topologies. This runs the topology creation for CDP and LLDP.\n'
f'The topologies are then merged in the specified order.\n'
f'I.e. -m CDP LLDP merges the CDP topology into the LLDP topology, overwriting\n'
f'the LLDP data in case there are conflicts.\n'
f'NOTE: static connection data from the user file will always merged with the\n'
f' highest priority',
)
parser.add_argument(
'-o', '--output-directory', type=str,
help='Directory name where to save the topology data.\n'
......
File added
......@@ -10,14 +10,15 @@
'tester ;-)\n'
'\n'
'Features:\n'
'- Reading connection data from the Checkmk inventory\n'
'- Adding user defined connections for connections not '
'included in the inventory\n'
'- handling differences between inventory neighbor names and '
'checkmk hostnames\n'
'- optimized for my CDP (default) and LLDP cache plugins\n'
'- can also be used with custom inventory plugins\n'
'- clean up old topologies\n'
'- Reading connection data from the checkmk HW/SW inventory.\n'
'- Handling differences between inventory neighbor names and '
'checkmk host names.\n'
'- Add custom connections for connections that are not in the '
'inventory\n'
'- Optimized for my CDP (default) and LLDP cache plugins\n'
'- Read and merge CDP and LLDP topologies\n'
'- Can also be used with custom inventory plugins\n'
'- Clean up old topologies\n'
'\n'
'For more information about the network visualization plugin '
'see: \n'
......@@ -55,7 +56,7 @@
'topology_data/create_topology_data.toml']},
'name': 'create_topology_data',
'title': 'Network Visualization data creation',
'version': '0.0.7-20231019',
'version': '0.0.8-20231020',
'version.min_required': '2.2.0p1',
'version.packaged': '2.2.0p11',
'version.usable_until': '2.3.0p1'}
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