From e6add58be72ccfa192bfdaef74d26333371d5f55 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Mon, 22 Jul 2024 21:26:33 +0200 Subject: [PATCH] update project --- README.md | 2 +- mkp/vsphere_topo-0.0.5-20240717.mkp | Bin 0 -> 7740 bytes .../vsphere_topo/agent_based/packages.py | 137 ++++++------------ .../vsphere_topo/constants.py | 43 ++++++ .../vsphere_topo/lib/utils.py | 129 ++++++++++++----- .../vsphere_topo/rulesets/packages.py | 2 +- source/packages/vsphere_topo | 7 +- 7 files changed, 187 insertions(+), 133 deletions(-) create mode 100644 mkp/vsphere_topo-0.0.5-20240717.mkp create mode 100644 source/cmk_addons_plugins/vsphere_topo/constants.py diff --git a/README.md b/README.md index 63d5cc5..76338db 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.5-20240714.mkp "vsphere_topo-0.0.5-20240714.mkp" +[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.5-20240717.mkp "vsphere_topo-0.0.5-20240717.mkp" # vSphere Topology Visualization This plugin uses the data from the _VMware ESX via vSphere_ special agent to create a topology of the vSphere environment.\ diff --git a/mkp/vsphere_topo-0.0.5-20240717.mkp b/mkp/vsphere_topo-0.0.5-20240717.mkp new file mode 100644 index 0000000000000000000000000000000000000000..736c43e65fad350c19a369c5a616d20d990612d9 GIT binary patch literal 7740 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 literal 0 HcmV?d00001 diff --git a/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py b/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py index dfb19c1..f03291e 100644 --- a/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py +++ b/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py @@ -16,10 +16,11 @@ # -> obsoletes 'Don\'t add vCenter as VM' # 2024-07-12: added support for Queried host is a host system # 2024-07-13: refactoring save topology/make default and add dummy's logic +# 2024-07-16: moved add_host/add_service/add_connection to lib/utils/TopoObjects/TopoConnections +# moved ruleset name constants to utils/ruleset_names.py from collections.abc import Mapping, Sequence from time import time_ns -from typing import Any from cmk.agent_based.v2 import ( CheckPlugin, @@ -32,13 +33,11 @@ from cmk.agent_based.v2 import ( render, ) from cmk.base.check_api import host_name -from cmk_addons.plugins.vsphere_topo.lib.utils import ( - BASE_TOPO_PATH, +from cmk_addons.plugins.vsphere_topo.constants import ( EMBLEM_CLUSTER, EMBLEM_DATA_CENTER, EMBLEM_DATA_STORE, ICON_VCENTER, - LiveStatusConnection, PARAM_CLUSTER, PARAM_DATA_CENTER, PARAM_DATA_STORE, @@ -48,6 +47,13 @@ from cmk_addons.plugins.vsphere_topo.lib.utils import ( PARAM_VCENTER, PARAM_VM_NAMES, RULE_SET_NAME_VSPHERE_TOPO, + TOPOLOGY_NAME, +) +from cmk_addons.plugins.vsphere_topo.lib.utils import ( + BASE_TOPO_PATH, + LiveStatusConnection, + TopoConnections, + TopoObjects, add_dummy_topologies, adjust_name, get_emblem, @@ -67,64 +73,14 @@ def discover_vsphere_topo( def check_vsphere_topo( - params: Mapping[str, Any], + params: Mapping[str, object], section_esx_vsphere_clusters: Section | None, section_esx_vsphere_virtual_machines: Sequence[Section] | None, section_esx_vsphere_datastores: Section | None, ) -> CheckResult: - def add_host( - host: str, - emblem: str | None = None, - icon: str | None = None, - link2core: bool = True, - obj_id_prefix: str = '', - ): - if objects.get(f'{obj_id_prefix}{host}') is not None: - return - - metadata = {} - if emblem or icon: - metadata = {'images': {}} - - if emblem is not None: - metadata['images'].update({'emblem': emblem}) # node image - - if icon is not None: - metadata['images'].update({'icon': icon}) # node icon - - objects[f'{obj_id_prefix}{host}'] = { - "name": host, - "link": {'core': host} if link2core else {}, - 'metadata': metadata, - } - - def add_service(host: str, service: str, emblem: str | None = None, link2core: bool = True): - obj_id = f'{service}@{host}' - if objects.get(obj_id) is not None: - return - - metadata = {} - if emblem is not None: - metadata = { - 'images': { - 'emblem': emblem, # node image - }, - } - - objects[obj_id] = { - "name": service, - "link": {'core': [host, service]} if link2core else {}, - 'metadata': metadata, - } - - def add_connection(left: str, right: str): - connection = [left, right] - connection.sort() - connections.append([connection, {'line_config': {'css_styles': {'stroke-dasharray': 'unset'}}}]) - start_time = time_ns() - objects = {} - connections = [] + objects = TopoObjects() + connections = TopoConnections() if section_esx_vsphere_clusters is not None: __clusters = { @@ -136,7 +92,7 @@ def check_vsphere_topo( } raw_vsphere_host: str = host_name().strip() - add_host( + objects.add_host( host=raw_vsphere_host, obj_id_prefix='vc', icon=get_emblem(ICON_VCENTER, params.get(PARAM_VCENTER)), @@ -145,32 +101,32 @@ def check_vsphere_topo( for cluster in section_esx_vsphere_clusters: data_center: str = section_esx_vsphere_clusters[cluster]['datacenter'].strip() - if objects.get(data_center) is None: - add_host( + if objects.topo_objects.get(data_center) is None: + objects.add_host( host=data_center, emblem=get_emblem(EMBLEM_DATA_CENTER, params.get(PARAM_DATA_CENTER)), link2core=False, ) - add_connection(data_center, vsphere_host) - add_host( + connections.add_connection(data_center, vsphere_host) + objects.add_host( host=cluster, emblem=get_emblem(EMBLEM_CLUSTER, params.get(PARAM_CLUSTER)), link2core=False ) - add_connection(cluster, data_center) + connections.add_connection(cluster, data_center) host_systems: Sequence[str] = section_esx_vsphere_clusters[cluster].get('hostsystems', '').split(',') for host_system in host_systems: esx_name: str = adjust_name(host_system, params.get(PARAM_HOST_SYSTEMS, {})) - add_host(host=esx_name) - add_connection(cluster, esx_name) + objects.add_host(host=esx_name) + connections.add_connection(cluster, esx_name) yield Result( state=State.OK, notice='VMware ESX via vSphere agent type of query: Queried host is the vCenter' ) else: # assuming the query type is ESXi host raw_vsphere_host: str = host_name().strip() - add_host(host=raw_vsphere_host) + objects.add_host(host=raw_vsphere_host) vsphere_host = raw_vsphere_host yield Result( state=State.OK, @@ -207,8 +163,8 @@ def check_vsphere_topo( for vm in section_esx_vsphere_virtual_machines: vm_name: str = adjust_name(vm['vm_name'], params.get(PARAM_VM_NAMES, {})) host_system: str = adjust_name(vm['hostsystem'], params.get(PARAM_HOST_SYSTEMS, {})) - add_host(host=vm_name) - add_connection(vm_name, host_system) + objects.add_host(host=vm_name) + connections.add_connection(vm_name, host_system) service_prefix: str = '' ds_services = None @@ -216,18 +172,18 @@ def check_vsphere_topo( if section_esx_vsphere_datastores is not None: data_stores_host: str = 'data_stores' # Anchor for data stores - add_host( + objects.add_host( host=data_stores_host, link2core=False, emblem=get_emblem(EMBLEM_DATA_STORE, params.get(PARAM_DATA_STORE)), ) for ds_name in section_esx_vsphere_datastores: - add_host( + objects.add_host( host=ds_name, link2core=False, emblem=get_emblem(EMBLEM_DATA_STORE, params.get(PARAM_DATA_STORE)), ) - add_connection(ds_name, data_stores_host) + connections.add_connection(ds_name, data_stores_host) if params.get(PARAM_DATA_STORE_AS_SERVICE) is True: query: str = ( @@ -242,12 +198,12 @@ def check_vsphere_topo( service_name: str = ds_service[0] service_id: str = f'{service_name}@{vsphere_host}' ds_name: str = service_name.split('fs_')[-1].split('Filesystem ')[-1] - add_service( + objects.add_service( host=vsphere_host, service=service_name, ) - add_connection(service_id, ds_name) - service_prefix = service_name.split(ds_name)[0] + connections.add_connection(service_id, ds_name) + service_prefix: str = service_name.split(ds_name)[0] query: str = ( 'GET services\n' @@ -258,46 +214,49 @@ def check_vsphere_topo( if (vm_to_data_stores := ls_connection.query(query=query)) is not None: for vm, data_stores in vm_to_data_stores: vm_name: str = adjust_name(vm, params.get(PARAM_VM_NAMES, {})) - if vm_name in objects: + if vm_name in objects.topo_objects: data_stores = data_stores.split(',') for data_store in data_stores: ds_name = data_store.strip().split(' ')[2] if ds_services is not None: service_name = f'{service_prefix}{ds_name}' service_id = f'{service_name}@{vsphere_host}' - add_connection(service_id, vm_name) + connections.add_connection(service_id, vm_name) else: - add_connection(ds_name, vm_name) + connections.add_connection(ds_name, vm_name) - connections.sort() - data_set_vsphere = { + connections.topo_connections.sort() + data_set = { 'version': 1, - 'name': 'vSphere', - 'objects': dict(sorted(objects.items())), - 'connections': connections, + 'name': TOPOLOGY_NAME, + 'objects': dict(sorted(objects.topo_objects.items())), + 'connections': connections.topo_connections, } - save_topology(data=data_set_vsphere, sub_directory=raw_vsphere_host) + save_topology(data=data_set, sub_directory=raw_vsphere_host) # workaround for backend is only picking up topologies from default folder add_dummy_topologies(sub_directory=raw_vsphere_host) # end workaround make_topo_default(sub_directory=raw_vsphere_host, make_default=params.get(PARAM_MAKE_DEFAULT, False)) - yield Result(state=State.OK, summary=f'Objects: {len(objects)}') - yield Result(state=State.OK, summary=f'Connections: {len(connections)}') - yield Result(state=State.OK, notice=f'Written to: {BASE_TOPO_PATH}/{raw_vsphere_host}/data_vsphere.json') + yield Result(state=State.OK, summary=f'Objects: {len(objects.topo_objects)}') + yield Result(state=State.OK, summary=f'Connections: {len(connections.topo_connections)}') + yield Result( + state=State.OK, + notice=f'Written to: {BASE_TOPO_PATH}/{raw_vsphere_host}/data_{TOPOLOGY_NAME.lower()}.json', + ) yield from check_levels( value=(time_ns() - start_time) / 1e9, label='Time taken', - metric_name='vsphere_topo_time_taken', + metric_name=f'{TOPOLOGY_NAME.lower()}_topo_time_taken', boundaries=(0, None), render_func=render.timespan, ) check_plugin_vsphere_topo = CheckPlugin( - name="vsphere_topo", - service_name="vSphere Topology", + name='vsphere_topo', + service_name=f'{TOPOLOGY_NAME} Topology', sections=[ 'esx_vsphere_clusters', 'esx_vsphere_virtual_machines', diff --git a/source/cmk_addons_plugins/vsphere_topo/constants.py b/source/cmk_addons_plugins/vsphere_topo/constants.py new file mode 100644 index 0000000..e58585f --- /dev/null +++ b/source/cmk_addons_plugins/vsphere_topo/constants.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2024-07-16 +# File : vsphere_topo/lib/ruelset_names.py + +from typing import Final + +EMBLEM_CLUSTER: Final[str] = 'icon_plugins_hw' +EMBLEM_DATA_CENTER: Final[str] = 'icon_cloud' +EMBLEM_DATA_STORE: Final[str] = 'icon_services_green' + +ICON_VCENTER: Final[str] = 'icon_topic_hosts' + +PARAM_ADD_DUMMY_TOPOLOGIES: Final[str] = 'add_dummy_topologies' +PARAM_CHANGE_CASE: Final[str] = 'change_case' +PARAM_CLUSTER: Final[str] = 'cluster' +PARAM_CUSTOM_EMBLEM: Final[str] = 'custom_emblem' +PARAM_DATA_CENTER: Final[str] = 'data_center' +PARAM_DATA_STORE: Final[str] = 'data_store' +PARAM_DATA_STORE_AS_SERVICE: Final[str] = 'data_sore_as_service' +PARAM_DEFAULT_EMBLEM: Final[str] = 'default_emblem' +PARAM_DONT_ADD_VC_AS_VM: Final[str] = 'dont_add_vc_as_vm' +PARAM_HOST_SYSTEMS: Final[str] = 'host_systems' +PARAM_KEEP_DOMAIN: Final[str] = 'keep_domain' +PARAM_LOWER: Final[str] = 'lower' +PARAM_MAKE_DEFAULT: Final[str] = 'make_default' +PARAM_NO_CHANGE: Final[str] = 'no_change' +PARAM_NO_EMBLEM: Final[str] = 'no_emblem' +PARAM_PREFIX: Final[str] = 'prefix' +PARAM_UPPER: Final[str] = 'upper' +PARAM_VCENTER: Final[str] = 'vcenter_icon' +PARAM_VM_NAMES: Final[str] = 'vm_names' + +PICTURE_TYPE_EMBLEM: Final[str] = 'emblem' +PICTURE_TYPE_ICON: Final[str] = 'icon' + +RULE_SET_NAME_VSPHERE_TOPO: Final[str] = 'vsphere_topo' +TOPOLOGY_NAME: Final[str] ='vSphere' diff --git a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py index 606ffcd..e969d59 100644 --- a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py +++ b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py @@ -12,46 +12,26 @@ from collections.abc import Mapping, MutableMapping, MutableSequence, Sequence from json import dumps as json_dunps, loads as json_loads from os import environ from pathlib import Path -from typing import Any, Final, Tuple +from typing import Final, Tuple from livestatus import MultiSiteConnection, SiteConfigurations, SiteId - -EMBLEM_CLUSTER: Final[str] = 'icon_plugins_hw' -EMBLEM_DATA_CENTER: Final[str] = 'icon_cloud' -EMBLEM_DATA_STORE: Final[str] = 'icon_services_green' - -ICON_VCENTER: Final[str] = 'icon_topic_hosts' - -PARAM_ADD_DUMMY_TOPOLOGIES: Final[str] = 'add_dummy_topologies' -PARAM_CHANGE_CASE: Final[str] = 'change_case' -PARAM_CLUSTER: Final[str] = 'cluster' -PARAM_CUSTOM_EMBLEM: Final[str] = 'custom_emblem' -PARAM_DATA_CENTER: Final[str] = 'data_center' -PARAM_DATA_STORE: Final[str] = 'data_store' -PARAM_DATA_STORE_AS_SERVICE: Final[str] = 'data_sore_as_service' -PARAM_DEFAULT_EMBLEM: Final[str] = 'default_emblem' -PARAM_DONT_ADD_VC_AS_VM: Final[str] = 'dont_add_vc_as_vm' -PARAM_HOST_SYSTEMS: Final[str] = 'host_systems' -PARAM_KEEP_DOMAIN: Final[str] = 'keep_domain' -PARAM_LOWER: Final[str] = 'lower' -PARAM_MAKE_DEFAULT: Final[str] = 'make_default' -PARAM_NO_CHANGE: Final[str] = 'no_change' -PARAM_NO_EMBLEM: Final[str] = 'no_emblem' -PARAM_PREFIX: Final[str] = 'prefix' -PARAM_UPPER: Final[str] = 'upper' -PARAM_VCENTER: Final[str] = 'vcenter_icon' -PARAM_VM_NAMES: Final[str] = 'vm_names' - -PICTURE_TYPE_EMBLEM: Final[str] = 'emblem' -PICTURE_TYPE_ICON: Final[str] = 'icon' - -RULE_SET_NAME_VSPHERE_TOPO: Final[str] = 'vsphere_topo' - -OMD_ROOT = environ["OMD_ROOT"] +from cmk_addons.plugins.vsphere_topo.constants import ( + PARAM_CHANGE_CASE, + PARAM_CUSTOM_EMBLEM, + PARAM_DEFAULT_EMBLEM, + PARAM_KEEP_DOMAIN, + PARAM_LOWER, + PARAM_NO_CHANGE, + PARAM_NO_EMBLEM, + PARAM_PREFIX, + PARAM_UPPER, + TOPOLOGY_NAME, +) +OMD_ROOT = environ['OMD_ROOT'] BASE_TOPO_PATH: Final[str] = f'{OMD_ROOT}/var/check_mk/topology/data' -def adjust_name(name: str, params: Mapping[str, Any]) -> str: +def adjust_name(name: str, params: Mapping[str, object]) -> str: class Case: upper: str = PARAM_UPPER lower: str = PARAM_LOWER @@ -149,8 +129,8 @@ def get_topologies() -> Sequence[str | None]: def add_dummy_topologies(sub_directory: str): path: str = f'{BASE_TOPO_PATH}/default' - if Path(path).exists() and not Path(f'{path}/data_vsphere.json').exists(): # don't overwrite existing topology - dummy_topology = {'version': 1, 'name': 'vSphere', 'objects': {}, 'connections': []} + if Path(path).exists() and not Path(f'{path}/data_{TOPOLOGY_NAME.lower()}.json').exists(): # don't overwrite existing topology + dummy_topology = {'version': 1, 'name': TOPOLOGY_NAME, 'objects': {}, 'connections': []} save_topology( data=dummy_topology, sub_directory='default', @@ -175,14 +155,14 @@ class LiveStatusConnection(object): if self.sites_mk.exists(): # make eval() "secure" # https://realpython.com/python-eval-function/#minimizing-the-security-issues-of-eval - _code = compile(self.sites_mk.read_text(), "<string>", "eval") + _code = compile(self.sites_mk.read_text(), '<string>', 'eval') allowed_names = ['sites', 'update'] for name in _code.co_names: if name not in allowed_names: raise NameError(f'Use of {name} in {self.sites_mk.name} not allowed.') sites_raw: MutableMapping = {} - eval(self.sites_mk.read_text(), {"__builtins__": {}}, {"sites": sites_raw}) + eval(self.sites_mk.read_text(), {'__builtins__': {}}, {'sites': sites_raw}) for site, data in sites_raw.items(): self.sites.update({site: { @@ -215,3 +195,74 @@ class LiveStatusConnection(object): return data else: return None + + +class TopoObjects(object): + def __init__(self) -> None: + self.topo_objects: MutableMapping[str, object] = {} + + def add_host( + self, + host: str, + emblem: str | None = None, + icon: str | None = None, + link2core: bool = True, + obj_id_prefix: str = '', + ): + if self.topo_objects.get(f'{obj_id_prefix}{host}') is not None: + return + + metadata = {} + if emblem or icon: + metadata = {'images': {}} + + if emblem is not None: + metadata['images'].update({'emblem': emblem}) # node image + + if icon is not None: + metadata['images'].update({'icon': icon}) # node icon + + self.topo_objects[f'{obj_id_prefix}{host}'] = { + 'name': host, + 'link': {'core': host} if link2core else {}, + 'metadata': metadata, + } + + def add_service( + self, + host: str, + service: str, + emblem: str | None = None, + link2core: bool = True, + ): + obj_id = f'{service}@{host}' + if self.topo_objects.get(obj_id) is not None: + return + + metadata = {} + if emblem is not None: + metadata = { + 'images': { + 'emblem': emblem, # node image + }, + } + + self.topo_objects[obj_id] = { + 'name': service, + 'link': {'core': [host, service]} if link2core else {}, + 'metadata': metadata, + } + + +class TopoConnections(object): + def __init__(self) -> None: + self.topo_connections: MutableSequence = [] + + def add_connection( + self, + left: str, + right: str, + ): + connection = [left, right] + connection.sort() + self.topo_connections.append([connection, {'line_config': {'css_styles': {'stroke-dasharray': 'unset'}}}]) diff --git a/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py b/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py index 974e6e0..e541adb 100644 --- a/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py +++ b/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py @@ -24,7 +24,7 @@ from cmk.rulesets.v1.form_specs import ( ) from cmk.rulesets.v1.form_specs.validators import LengthInRange from cmk.rulesets.v1.rule_specs import CheckParameters, HostCondition, Topic -from cmk_addons.plugins.vsphere_topo.lib.utils import ( +from cmk_addons.plugins.vsphere_topo.constants import ( EMBLEM_CLUSTER, EMBLEM_DATA_CENTER, EMBLEM_DATA_STORE, diff --git a/source/packages/vsphere_topo b/source/packages/vsphere_topo index 203c698..2215409 100644 --- a/source/packages/vsphere_topo +++ b/source/packages/vsphere_topo @@ -5,14 +5,15 @@ '\n' 'Topolgy is created by: vCenter -> data center(s) ' '->Cluster(s) -> ESX host(s) -> VM(s)\n', - 'download_url': 'https://thl-cmk.hopto.org', + 'download_url': 'https://thl-cmk.hopto.org/gitlab/checkmk/various/vsphere_topo', 'files': {'cmk_addons_plugins': ['vsphere_topo/agent_based/packages.py', 'vsphere_topo/rulesets/packages.py', 'vsphere_topo/lib/utils.py', - 'vsphere_topo/graphing/packages.py']}, + 'vsphere_topo/graphing/packages.py', + 'vsphere_topo/constants.py']}, 'name': 'vsphere_topo', 'title': 'vSphere Topologie', - 'version': '0.0.5-20240714', + 'version': '0.0.5-20240717', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.usable_until': '2.4.0b1'} -- GitLab