diff --git a/README.md b/README.md index b5a342b31e48d2b4cad8ac2eebe262b2652a46da..dfc7b17db680b740bb4d0e6ab5632f85aee03ee1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.6-20240729.mkp "vsphere_topo-0.0.6-20240729.mkp" +[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.7-20240801.mkp "vsphere_topo-0.0.7-20240801.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.7-20240801.mkp b/mkp/vsphere_topo-0.0.7-20240801.mkp new file mode 100644 index 0000000000000000000000000000000000000000..89ccc3529641c39ea5ee6509ec00d18b4779f8f9 Binary files /dev/null and b/mkp/vsphere_topo-0.0.7-20240801.mkp differ diff --git a/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py b/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py index 791db5fc7b4521b98208ea6fee50b2dbb39b5cb1..ea6baf7e012bfda77b001629c30ae9a126d121f4 100644 --- a/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py +++ b/source/cmk_addons_plugins/vsphere_topo/agent_based/vsphere_topo.py @@ -21,6 +21,7 @@ # 2024-07-25: fixed crash if VM has no data store # 2024-07-29: added option to ignore powered off VMs # added option to ignore VMs by name (regex) +# 2024-07-31: added option to map vSphere names to CMK/topology names for data center, cluster, hosts and VMs from collections.abc import Mapping, Sequence from re import compile as re_compile @@ -51,6 +52,7 @@ from cmk_addons.plugins.vsphere_topo.constants import ( PARAM_IGNORE_POWERED_OFF_VMS, PARAM_IGNORE_VM_NAME_REGEX, PARAM_MAKE_DEFAULT, + PARAM_MAP_NAMES, PARAM_VCENTER, PARAM_VM_NAMES, RULE_SET_NAME_VSPHERE_TOPO, @@ -64,6 +66,7 @@ from cmk_addons.plugins.vsphere_topo.lib.utils import ( add_dummy_topologies, adjust_name, get_emblem, + get_name_map, make_topo_default, save_topology, ) @@ -90,6 +93,9 @@ def check_vsphere_topo( connections: TopoConnections = TopoConnections() ignored_powered_off_vms: int = 0 ignored_by_name_vms: int = 0 + + name_map = get_name_map(params.get(PARAM_MAP_NAMES, [])) + if ignore_by_name_str := ')|('.join(params.get(PARAM_IGNORE_VM_NAME_REGEX, [])): re_ignore_vms = re_compile(f'({ignore_by_name_str})') else: @@ -112,8 +118,9 @@ def check_vsphere_topo( ) vsphere_host = f'vc{raw_vsphere_host}' - for cluster in section_esx_vsphere_clusters: - data_center: str = section_esx_vsphere_clusters[cluster]['datacenter'].strip() + for raw_cluster in section_esx_vsphere_clusters: + data_center: str = section_esx_vsphere_clusters[raw_cluster]['datacenter'].strip() + data_center = name_map.get(data_center, data_center) if objects.topo_objects.get(data_center) is None: objects.add_host( host=data_center, @@ -121,6 +128,7 @@ def check_vsphere_topo( link2core=False, ) connections.add_connection(data_center, vsphere_host) + cluster = name_map.get(raw_cluster, raw_cluster) objects.add_host( host=cluster, emblem=get_emblem(EMBLEM_CLUSTER, params.get(PARAM_CLUSTER)), @@ -128,9 +136,10 @@ def check_vsphere_topo( ) connections.add_connection(cluster, data_center) - host_systems: Sequence[str] = section_esx_vsphere_clusters[cluster].get('hostsystems', '').split(',') + host_systems: Sequence[str] = section_esx_vsphere_clusters[raw_cluster].get('hostsystems', '').split(',') for host_system in host_systems: esx_name: str = adjust_name(host_system, params.get(PARAM_HOST_SYSTEMS, {})) + esx_name = name_map.get(esx_name, esx_name) objects.add_host(host=esx_name) connections.add_connection(cluster, esx_name) yield Result( @@ -177,7 +186,9 @@ def check_vsphere_topo( if params.get(PARAM_IGNORE_POWERED_OFF_VMS) is not True or vm.get('powerstate') != 'poweredOff': vm_name: str = adjust_name(vm['vm_name'], params.get(PARAM_VM_NAMES, {})) if re_ignore_vms is None or re_ignore_vms.match(vm_name) is None: + vm_name = name_map.get(vm_name, vm_name) host_system: str = adjust_name(vm['hostsystem'], params.get(PARAM_HOST_SYSTEMS, {})) + host_system = name_map.get(host_system, host_system) objects.add_host(host=vm_name) connections.add_connection(vm_name, host_system) else: diff --git a/source/cmk_addons_plugins/vsphere_topo/constants.py b/source/cmk_addons_plugins/vsphere_topo/constants.py index 2036aeada4f97b35bb7f1933dde2e41758103e0d..e7b40d643c6235f9e4c21a3412255a65baa55f3b 100644 --- a/source/cmk_addons_plugins/vsphere_topo/constants.py +++ b/source/cmk_addons_plugins/vsphere_topo/constants.py @@ -31,6 +31,9 @@ PARAM_IGNORE_VM_NAME_REGEX: Final[str] = 'ignore_vms_by_name' PARAM_KEEP_DOMAIN: Final[str] = 'keep_domain' PARAM_LOWER: Final[str] = 'lower' PARAM_MAKE_DEFAULT: Final[str] = 'make_default' +PARAM_MAP_NAMES: Final[str] = 'map_names' +PARAM_MAP_NAME_CMK: Final[str] = 'name_cmk' +PARAM_MAP_NAME_VSPHERE: Final[str] = 'name_vsphere' PARAM_NO_CHANGE: Final[str] = 'no_change' PARAM_NO_EMBLEM: Final[str] = 'no_emblem' PARAM_PREFIX: Final[str] = 'prefix' diff --git a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py index e969d5970c1d75bc35659ab5bfa940f0d4974b9b..9f4b36a307ba14a6e94d5189b41eb1a5c6dc9eda 100644 --- a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py +++ b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py @@ -12,6 +12,7 @@ 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 re import compile as re_compile from typing import Final, Tuple from livestatus import MultiSiteConnection, SiteConfigurations, SiteId @@ -21,6 +22,8 @@ from cmk_addons.plugins.vsphere_topo.constants import ( PARAM_DEFAULT_EMBLEM, PARAM_KEEP_DOMAIN, PARAM_LOWER, + PARAM_MAP_NAME_CMK, + PARAM_MAP_NAME_VSPHERE, PARAM_NO_CHANGE, PARAM_NO_EMBLEM, PARAM_PREFIX, @@ -31,6 +34,17 @@ OMD_ROOT = environ['OMD_ROOT'] BASE_TOPO_PATH: Final[str] = f'{OMD_ROOT}/var/check_mk/topology/data' +def get_name_map(mappings: Sequence): + re_hostname = re_compile(r'^[0-9a-zA-Z\.\-\_]+$') + name_map = {} + + for mapping in mappings: + if re_hostname.match(mapping[PARAM_MAP_NAME_CMK]) is not None: + name_map[mapping[PARAM_MAP_NAME_VSPHERE]] = mapping[PARAM_MAP_NAME_CMK] + + return name_map + + def adjust_name(name: str, params: Mapping[str, object]) -> str: class Case: upper: str = PARAM_UPPER diff --git a/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py b/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py index 4ce336730ac249e685c1fc744a6d2d2221687fa5..f24b58282d69ba7d6f05e01ba7b62f1c3b576179 100644 --- a/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py +++ b/source/cmk_addons_plugins/vsphere_topo/rulesets/vsphere_topo.py @@ -11,8 +11,9 @@ # removed PARAM_ADD_DUMMY_TOPOLOGIES and PARAM_DONT_ADD_VC_AS_VM from collections.abc import Mapping, Sequence +from re import compile as re_compile -from cmk.rulesets.v1 import Help, Label, Title +from cmk.rulesets.v1 import Help, Label, Title, Message from cmk.rulesets.v1.form_specs import ( CascadingSingleChoice, CascadingSingleChoiceElement, @@ -20,12 +21,12 @@ from cmk.rulesets.v1.form_specs import ( DictElement, Dictionary, FixedValue, + List, SingleChoice, SingleChoiceElement, String, - List, ) -from cmk.rulesets.v1.form_specs.validators import LengthInRange +from cmk.rulesets.v1.form_specs.validators import LengthInRange, MatchRegex from cmk.rulesets.v1.rule_specs import CheckParameters, HostCondition, Topic from cmk_addons.plugins.vsphere_topo.constants import ( # PARAM_ADD_DUMMY_TOPOLOGIES, @@ -47,6 +48,9 @@ from cmk_addons.plugins.vsphere_topo.constants import ( PARAM_KEEP_DOMAIN, PARAM_LOWER, PARAM_MAKE_DEFAULT, + PARAM_MAP_NAMES, + PARAM_MAP_NAME_CMK, + PARAM_MAP_NAME_VSPHERE, PARAM_NO_CHANGE, PARAM_NO_EMBLEM, PARAM_PREFIX, @@ -194,14 +198,40 @@ def _parameter_form() -> Dictionary: PARAM_IGNORE_VM_NAME_REGEX: DictElement( parameter_form=List( title=Title('Ignore VMs by name (regex)'), - element_template=String( - title=Title('add regex string') - ), + element_template=String(), help_text=Help( 'The regex strings will be applied after the upper/lower case and prefix ' 'change to the VM names. If there more than one regex string the will be "OR" connected.' ), )), + PARAM_MAP_NAMES: DictElement( + parameter_form=List( + title=Title('Map vSphere names to CMK names'), + element_template=Dictionary( + elements={ + PARAM_MAP_NAME_VSPHERE: DictElement( + parameter_form=String( + title=Title('vSphere name'), + ), + required=True, + ), + PARAM_MAP_NAME_CMK: DictElement( + parameter_form=String( + title=Title('Checkmk name'), + custom_validate=(MatchRegex( + regex=r'^[0-9a-zA-Z\.\-\_]+$', + error_msg=Message( + 'Your input does not match the required format. ' + 'Only "0-9a-zA-Z_-." are allowed.' + ) + ),) + ), + required=True, + ) + } + ), + help_text=Help(''), + )), # PARAM_DONT_ADD_VC_AS_VM: DictElement( # render_only=True, # parameter_form=FixedValue( diff --git a/source/packages/vsphere_topo b/source/packages/vsphere_topo index 8ec8c4e2fba6e6fd1052d67c5ad4960e8459baba..f5b7d53ec66f08f8d847e07ded08a8b927739c27 100644 --- a/source/packages/vsphere_topo +++ b/source/packages/vsphere_topo @@ -13,7 +13,7 @@ 'vsphere_topo/rulesets/vsphere_topo.py']}, 'name': 'vsphere_topo', 'title': 'vSphere Topologie', - 'version': '0.0.6-20240729', + 'version': '0.0.7-20240801', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.usable_until': '2.4.0b1'}