diff --git a/README.md b/README.md index 9209cf4aca73434dbe4fed878d996a1102c59651..6362bf486e314baff2f5fc70bd93d46fe4ab3630 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/packagee-0.1.2-20230706.mkp "package-0.1.2-20230706.mkp" +[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.1-20240709.mkp "vsphere_topo-0.0.1-20240709.mkp" # Title A short description about the plugin diff --git a/mkp/vsphere_topo-0.0.1-20240709.mkp b/mkp/vsphere_topo-0.0.1-20240709.mkp new file mode 100644 index 0000000000000000000000000000000000000000..488875b9d5a288c645153386c117138b2394fd94 Binary files /dev/null and b/mkp/vsphere_topo-0.0.1-20240709.mkp differ diff --git a/source/checkman/.gitkeep b/source/checkman/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/source/checkman/vsphere_topo b/source/checkman/vsphere_topo deleted file mode 100644 index 08ef898bcf6eb7a7979de60090d54f9719bbbc5b..0000000000000000000000000000000000000000 --- a/source/checkman/vsphere_topo +++ /dev/null @@ -1,45 +0,0 @@ -title: Dummy check man page - used as template for new check manuals -agents: linux, windows, aix, solaris, hpux, vms, freebsd, snmp -catalog: see modules/catalog.py for possible values -license: GPL -distribution: check_mk -description: - Describe here: (1) what the check actually does, (2) under which - circumstances it goes warning/critical, (3) which devices are supported - by the check, (4) if the check requires a separated plugin or - tool or separate configuration on the target host. - -item: - Describe the syntax and meaning of the check's item here. Provide all - information one needs if coding a manual check with {checks +=} in {main.mk}. - Give an example. If the check uses {None} as sole item, - then leave out this section. - -examples: - # Give examples for configuration in {main.mk} here. If the check has - # configuration variable, then give example for them here. - - # set default levels to 40 and 60 percent: - foo_default_values = (40, 60) - - # another configuration variable here: - inventory_foo_filter = [ "superfoo", "superfoo2" ] - -perfdata: - Describe precisely the number and meaning of performance variables - the check sends. If it outputs no performance data, then leave out this - section. - -inventory: - Describe how the inventory for the check works. Which items - will it find? Describe the influence of check specific - configuration parameters to the inventory. - -[parameters] -foofirst(int): describe the first parameter here (if parameters are grouped - as tuple) -fooother(string): describe another parameter here. - -[configuration] -foo_default_levels(int, int): Describe global configuration variable of - foo here. Important: also tell the user how they are preset. diff --git a/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py b/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py new file mode 100644 index 0000000000000000000000000000000000000000..912b4c40253d7360badd221f2ceca267208b3c15 --- /dev/null +++ b/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py @@ -0,0 +1,291 @@ +#!/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-05 +# File : vsphere_topo/agent_based/packages.py + +from collections.abc import Mapping, Sequence +from time import time_ns +from typing import Any + +from cmk.agent_based.v2 import ( + CheckPlugin, + CheckResult, + DiscoveryResult, + Result, + Service, + State, +) +from cmk.base.check_api import host_name +from cmk_addons.plugins.vsphere_topo.lib.utils import ( + EMBLEM_CLUSTER, + EMBLEM_DATA_CENTER, + EMBLEM_DATA_STORE, + LiveStatusConnection, + OMD_ROOT, + PARAM_ADD_DUMMY_TOPOLOGIES, + PARAM_CLUSTER, + PARAM_DATA_CENTER, + PARAM_DATA_STORE, + PARAM_DATA_STORE_AS_SERVICE, + PARAM_DONT_ADD_VC_AS_VM, + PARAM_HOST_SYSTEMS, + PARAM_MAKE_DEFAULT, + PARAM_VM_NAMES, + RULE_SET_NAME_VSPHERE_TOPO, + adjust_name, + get_emblem, + save_data_to_file, +) + +Section = Mapping[str, object] + + +def discover_vsphere_topo( + section_esx_vsphere_clusters: Section | None, + section_esx_vsphere_virtual_machines: Sequence[Section] | None, + section_esx_vsphere_datastores: Section | None, +) -> DiscoveryResult: + yield Service() + + +def check_vsphere_topo( + params: Mapping[str, Any], + 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, link2core: bool = True): + if objects.get(host) is not None: + return + + metadata = {} + if emblem is not None: + metadata = { + 'images': { + 'emblem': emblem, # node image + }, + } + + objects[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 = [] + + vsphere_host: str = host_name().strip() + add_host(host=vsphere_host) + + __clusters = { + 'HA': { + 'datacenter': 'datacenter-21', + 'hostsystems': 'esxi01, esxi02', + 'vms': 'vmname01, vmname02, vmname03' + } + } + + if section_esx_vsphere_clusters is None: + yield Result(state=State.UNKNOWN, summary='Found no vSphere data centers/clusters') + return + + 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( + host=data_center, + emblem=get_emblem(EMBLEM_DATA_CENTER, params.get(PARAM_DATA_CENTER)), + link2core=False, + ) + add_connection(data_center, vsphere_host) + + add_host( + host=cluster, + emblem=get_emblem(EMBLEM_CLUSTER, params.get(PARAM_CLUSTER)), + link2core=False + ) + 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) + + __VMs = [ + { + 'vm_name': 'vmname01', + 'hostsystem': 'esxi01', + 'powerstate': 'poweredOff', + 'guest_os': 'Microsoft Windows Server 2008 R2 (64-bit)', + 'compatibility': 'vmx-10', + 'uuid': '420354bd-bee0-88d5-053c-d4f424106b0f' + }, + { + 'vm_name': 'vmname02', + 'hostsystem': 'esxi02', + 'powerstate': 'poweredOn', + 'guest_os': 'Microsoft Windows Server 2019 (64-bit)', + 'compatibility': 'vmx-19', + 'uuid': '422eba9f-0327-2da0-b546-f5a5e5dfdb68' + }, + { + 'vm_name': 'vmname03', + 'hostsystem': 'esxi01', + 'powerstate': 'poweredOn', + 'guest_os': 'Other 3.x or later Linux (64-bit)', + 'compatibility': 'vmx-11', + 'uuid': '422e3863-b7de-dc55-74f8-6dc9c159b36d' + } + ] + + if section_esx_vsphere_virtual_machines is not None: + for vm in section_esx_vsphere_virtual_machines: + vm_name: str = adjust_name(vm['vm_name'], params.get(PARAM_VM_NAMES, {})) + + if params.get(PARAM_DONT_ADD_VC_AS_VM) is True and vm_name.lower() == vsphere_host.lower(): + continue + host_system: str = adjust_name(vm['hostsystem'], params.get(PARAM_HOST_SYSTEMS, {})) + add_host(host=vm_name) + add_connection(vm_name, host_system) + + service_prefix: str = '' + ds_services = None + ls_connection = LiveStatusConnection() + + if section_esx_vsphere_datastores is not None: + data_stores_host: str = 'data_stores' # Anchor for data stores + 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( + host=ds_name, + link2core=False, + emblem=get_emblem(EMBLEM_DATA_STORE, params.get(PARAM_DATA_STORE)), + ) + add_connection(ds_name, data_stores_host) + + if params.get(PARAM_DATA_STORE_AS_SERVICE) is True: + query: str = ( + 'GET services\n' + 'Columns: service_description\n' + 'Filter: service_check_command ~ ^check_mk-esx_vsphere_datastores(!.*)?\n' + f'Filter: host_name = {vsphere_host}\n' + 'OutputFormat: python3\n' + ) + if (ds_services := ls_connection.query(query=query)) is not None: + for ds_service in ds_services: + 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( + host=vsphere_host, + service=service_name, + ) + add_connection(service_id, ds_name) + service_prefix = service_name.split(ds_name)[0] + + query: str = ( + 'GET services\n' + 'Columns: host_name long_plugin_output\n' + 'Filter: description = ESX Datastores\n' + 'OutputFormat: python3\n' + ) + 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 params.get(PARAM_DONT_ADD_VC_AS_VM) is True and vm_name.lower() == vsphere_host.lower(): + continue + if vm_name in 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) + else: + add_connection(ds_name, vm_name) + + connections.sort() + data_set_vsphere = { + 'version': 1, + 'name': 'vSphere', + 'objects': dict(sorted(objects.items())), + 'connections': connections, + } + + # workaround for missing topology + path: str = f'{OMD_ROOT}/var/check_mk/topology/data/{vsphere_host}' + if params.get(PARAM_ADD_DUMMY_TOPOLOGIES) is True: + data_sets = [ + {'version': 1, 'name': 'cdp', 'objects': {}, 'connections': []}, + {'version': 1, 'name': 'lldp', 'objects': {}, 'connections': []}, + {'version': 1, 'name': 'static', 'objects': {}, 'connections': []}, + {'version': 1, 'name': 'l3v4', 'objects': {}, 'connections': []}, + data_set_vsphere + ] + else: + data_sets = [data_set_vsphere] + for data_set in data_sets: + file: str = f'data_{data_set["name"].lower()}.json' + save_data_to_file( + data=data_set, + file=file, + make_default=params.get(PARAM_MAKE_DEFAULT, False), + path=path, + ) + + 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: {path}/{file}') + yield Result(state=State.OK, summary=f'Time taken: {((time_ns() - start_time) / 1e9):.2}/s') + + +check_plugin_vsphere_topo = CheckPlugin( + name="vsphere_topo", + service_name="vSphere Topology", + sections=[ + 'esx_vsphere_clusters', + 'esx_vsphere_virtual_machines', + 'esx_vsphere_datastores', + ], + check_function=check_vsphere_topo, + discovery_function=discover_vsphere_topo, + check_ruleset_name=RULE_SET_NAME_VSPHERE_TOPO, + check_default_parameters={}, +) diff --git a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..f32e7177b73dd24b4c7bd247e29097f48ee9f517 --- /dev/null +++ b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py @@ -0,0 +1,164 @@ +#!/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-06 +# File : vsphere_topo/lib/utils.py + +from collections.abc import Mapping, MutableMapping, MutableSequence +from json import dumps as json_dunps +from os import environ +from pathlib import Path +from typing import Any, 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' + +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_VM_NAMES: Final[str] = 'vm_names' + +RULE_SET_NAME_VSPHERE_TOPO: Final[str] = 'vsphere_topo' + +OMD_ROOT = environ["OMD_ROOT"] + + +def adjust_name(name: str, params: Mapping[str, Any]) -> str: + class Case: + upper: str = PARAM_UPPER + lower: str = PARAM_LOWER + no_change: str = PARAM_NO_CHANGE + + if params.get(PARAM_KEEP_DOMAIN) is None: + name = name.split('.')[0] + + match params.get(PARAM_CHANGE_CASE, PARAM_NO_CHANGE): + case Case.upper: + name = name.upper() + case Case.lower: + name = name.lower() + case Case.no_change | _: # all else + pass + + if (prefix := params.get(PARAM_PREFIX)) is not None: + name = f'{prefix.strip()}{name.strip()}' + + return name.strip() + + +def get_emblem(emblem: str, params: Tuple[str, bool | str] | None = None) -> str | None: + class Emblem: + no_emblem: str = PARAM_NO_EMBLEM + default_emblem: str = PARAM_DEFAULT_EMBLEM + custom_emblem: str = PARAM_CUSTOM_EMBLEM + + match params: + case None: + return emblem + case (Emblem.no_emblem, True): + return None + case (Emblem.default_emblem, True): + return emblem + case _: # custom_emblem + return params[1].strip() + + +def save_data_to_file(data: Mapping, path: str, file: str, make_default: bool) -> None: + """ + Save the data as json file. + Args: + data: the topology data + path: the path were to save the data + file: the file name to save the data in + make_default: if True, create the symlink "default" with path as target + + Returns: + None + """ + + path_file = f'{path}/{file}' + save_file = Path(f'{path_file}') + save_file.parent.mkdir(exist_ok=True, parents=True) + save_file.write_text(json_dunps(data)) + + parent_path = Path(f'{path}').parent + if not Path(f'{parent_path}/default').exists(): + make_default = True + if make_default: + Path(f'{parent_path}/default').unlink(missing_ok=True) + Path(f'{parent_path}/default').symlink_to(target=Path(path), target_is_directory=True) + + +# +# live status +# + +class LiveStatusConnection(object): + def __init__(self): + self.sites: SiteConfigurations = SiteConfigurations({}) + self.sites_mk = Path(f'{OMD_ROOT}/etc/check_mk/multisite.d/sites.mk') + self.socket_path = f'unix:{OMD_ROOT}/tmp/run/live' + 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") + 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}) + + for site, data in sites_raw.items(): + self.sites.update({site: { + 'alias': data['alias'], + 'timeout': data['timeout'], + }}) + if data['socket'] == ('local', None): + self.sites[site]['socket'] = self.socket_path + else: + protocol, socket = data['socket'] + address, port = socket['address'] + self.sites[site]['socket'] = f'{protocol}:{address}:{port}' + self.sites[site]['tls'] = socket['tls'] + else: + self.sites.update({SiteId('local'): { + 'alias': 'Local site', + 'timeout': 5, + 'socket': self.socket_path + }}) + + self.c = MultiSiteConnection(self.sites) + dead_sites = [site['site']['alias'] for site in self.c.dead_sites().values()] + if dead_sites: + self.c.set_only_sites(self.c.alive_sites()) + + def query(self, query: str): + data: MutableSequence[Tuple[str, str]] = self.c.query(query=query) + + if data: + return data + else: + return None diff --git a/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py b/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py new file mode 100644 index 0000000000000000000000000000000000000000..2133a73642f5e12f1a66cc882b4a39e800e6c61d --- /dev/null +++ b/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py @@ -0,0 +1,169 @@ +#!/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-06 +# File : vsphere_topo/rulesets/packages.py + +from collections.abc import Mapping, Sequence + +from cmk.rulesets.v1 import Label, Title +from cmk.rulesets.v1.form_specs import ( + CascadingSingleChoice, + CascadingSingleChoiceElement, + DefaultValue, + DictElement, + Dictionary, + FixedValue, + SingleChoice, + SingleChoiceElement, + String, +) + +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 ( + EMBLEM_CLUSTER, + EMBLEM_DATA_CENTER, + EMBLEM_DATA_STORE, + PARAM_ADD_DUMMY_TOPOLOGIES, + PARAM_CHANGE_CASE, + PARAM_CLUSTER, + PARAM_CUSTOM_EMBLEM, + PARAM_DATA_CENTER, + PARAM_DATA_STORE, + PARAM_DATA_STORE_AS_SERVICE, + PARAM_DEFAULT_EMBLEM, + PARAM_DONT_ADD_VC_AS_VM, + PARAM_HOST_SYSTEMS, + PARAM_KEEP_DOMAIN, + PARAM_LOWER, + PARAM_MAKE_DEFAULT, + PARAM_NO_CHANGE, + PARAM_NO_EMBLEM, + PARAM_PREFIX, + PARAM_UPPER, + PARAM_VM_NAMES, + RULE_SET_NAME_VSPHERE_TOPO, +) + +adjust_names_elements: Mapping[str, DictElement] = { + PARAM_KEEP_DOMAIN: DictElement( + parameter_form=FixedValue( + title=Title('Keep domain name'), + label=Label('The domain name will not be cut'), + value=True, + )), + PARAM_CHANGE_CASE: DictElement( + parameter_form=SingleChoice( + title=Title('Change case'), + elements=[ + SingleChoiceElement(name=PARAM_UPPER, title=Title('All upper case')), + SingleChoiceElement(name=PARAM_LOWER, title=Title('All lower case')), + SingleChoiceElement(name=PARAM_NO_CHANGE, title=Title('Don\'t change case')) + ], + prefill=DefaultValue(PARAM_NO_CHANGE) + )), + PARAM_PREFIX: DictElement( + parameter_form=String( + title=Title('Name prefix'), + custom_validate=(LengthInRange(min_value=1),) + )), +} + + +def get_emblem_element(default_emblem) -> Sequence[CascadingSingleChoiceElement]: + return [ + CascadingSingleChoiceElement( + name=PARAM_NO_EMBLEM, + title=Title('No custom emblem'), + parameter_form=FixedValue( + value=True, + label=Label('No custom emblem will be used') + )), + CascadingSingleChoiceElement( + name=PARAM_DEFAULT_EMBLEM, + title=Title('Use default emblem'), + parameter_form=FixedValue( + value=True, + label=Label(f'Emblem "{default_emblem}" will be used') + )), + CascadingSingleChoiceElement( + name=PARAM_CUSTOM_EMBLEM, + title=Title('Use custom emblem'), + parameter_form=String( + custom_validate=(LengthInRange(min_value=1),), + prefill=DefaultValue(default_emblem), + )) + ] + + +def _parameter_form() -> Dictionary: + return Dictionary( + elements={ + PARAM_HOST_SYSTEMS: DictElement( + parameter_form=Dictionary( + title=Title('Adjust ESXi host names'), + elements=adjust_names_elements + )), + PARAM_VM_NAMES: DictElement( + parameter_form=Dictionary( + title=Title('Adjust VM names'), + elements=adjust_names_elements + )), + PARAM_CLUSTER: DictElement( + parameter_form=CascadingSingleChoice( + title=Title('Cluster emblem'), + elements=get_emblem_element(EMBLEM_CLUSTER), + prefill=DefaultValue(PARAM_DEFAULT_EMBLEM) + )), + PARAM_DATA_CENTER: DictElement( + parameter_form=CascadingSingleChoice( + title=Title('Datacenter emblem'), + elements=get_emblem_element(EMBLEM_DATA_CENTER), + prefill=DefaultValue(PARAM_DEFAULT_EMBLEM) + )), + PARAM_DATA_STORE: DictElement( + parameter_form=CascadingSingleChoice( + title=Title('Datastore emblem'), + elements=get_emblem_element(EMBLEM_DATA_STORE), + prefill=DefaultValue(PARAM_DEFAULT_EMBLEM) + )), + PARAM_DATA_STORE_AS_SERVICE: DictElement( + parameter_form=FixedValue( + title=Title('Add data store service'), + label=Label('enabled'), + value=True + )), + PARAM_MAKE_DEFAULT: DictElement( + parameter_form=FixedValue( + title=Title('Make default'), + label=Label('This will be the default topology'), + value=True + )), + PARAM_DONT_ADD_VC_AS_VM: DictElement( + parameter_form=FixedValue( + title=Title('Don\'t add vCenter as VM'), + label=Label('The vCenter will not be added as VM'), + value=True + )), + PARAM_ADD_DUMMY_TOPOLOGIES: DictElement( + parameter_form=FixedValue( + title=Title('Add dummy topologies'), + label=Label('Adds empty CDP, LLDP, L3v4 and STATIC topology'), + value=True + )), + } + ) + + +rule_spec_vsphere_topo = CheckParameters( + name=RULE_SET_NAME_VSPHERE_TOPO, + topic=Topic.APPLICATIONS, + parameter_form=_parameter_form, + title=Title('vSphere Topology'), + condition=HostCondition(), +) diff --git a/source/packages/vsphere_topo b/source/packages/vsphere_topo new file mode 100644 index 0000000000000000000000000000000000000000..62492c4615b4a79fbc72f9ba98419fb1606d02f9 --- /dev/null +++ b/source/packages/vsphere_topo @@ -0,0 +1,17 @@ +{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', + 'description': 'Creates the vSphere topology, based on the data from the ESXI ' + 'special agent (esx_vsphere_clusters, ' + 'esx_vsphere_virtual_machines sections).\n' + '\n' + 'Topolgy is created by: vCenter -> data center(s) ' + '->Cluster(s) -> ESX host(s) -> VM(s)\n', + 'download_url': 'https://thl-cmk.hopto.org', + 'files': {'cmk_addons_plugins': ['vsphere_topo/agent_based/packages.py', + 'vsphere_topo/rulesets/packages.py', + 'vsphere_topo/lib/utils.py']}, + 'name': 'vsphere_topo', + 'title': 'vSphere Topologie', + 'version': '0.0.1-20240709', + 'version.min_required': '2.3.0b1', + 'version.packaged': 'cmk-mkp-tool 0.2.0', + 'version.usable_until': '2.4.0b1'}