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

update project

parent de45910d
No related branches found
No related tags found
No related merge requests found
[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.2-20240709.mkp "vsphere_topo-0.0.2-20240709.mkp"
[PACKAGE]: ../../raw/master/mkp/vsphere_topo-0.0.3-20240711.mkp "vsphere_topo-0.0.3-20240711.mkp"
# vSphere Topology Visualization
This plugin uses the data from the _VMware ESX via vSphere_ spezial agent to create a topolofy of the vSphere environment.
......
File added
......@@ -9,8 +9,14 @@
# File : vsphere_topo/agent_based/packages.py
# 2024-07-10: added time taken as metric
# 2024-07-11: added clearer error message for missing section_esx_vsphere_clusters section
# added automatic workaround for backend is only picking up topologies from default folder
# -> obsoletes 'Add dummy topologies'
# added vCenter twice (once as vCenter once as vM) with different object IDs
# -> obsoletes 'Don\'t add vCenter as VM'
from collections.abc import Mapping, Sequence
from pathlib import Path
from time import time_ns
from typing import Any
......@@ -29,20 +35,21 @@ from cmk_addons.plugins.vsphere_topo.lib.utils import (
EMBLEM_CLUSTER,
EMBLEM_DATA_CENTER,
EMBLEM_DATA_STORE,
ICON_VCENTER,
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_VCENTER,
PARAM_VM_NAMES,
RULE_SET_NAME_VSPHERE_TOPO,
adjust_name,
get_emblem,
get_topologies,
save_data_to_file,
)
......@@ -63,19 +70,27 @@ def check_vsphere_topo(
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:
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': {
'emblem': emblem, # node image
},
}
metadata['images'].update({'emblem': emblem}) # node image
if icon is not None:
metadata['images'].update({'icon': icon}) # node icon
objects[host] = {
objects[f'{obj_id_prefix}{host}'] = {
"name": host,
"link": {'core': host} if link2core else {},
'metadata': metadata,
......@@ -109,8 +124,14 @@ def check_vsphere_topo(
objects = {}
connections = []
vsphere_host: str = host_name().strip()
add_host(host=vsphere_host)
raw_vsphere_host: str = host_name().strip()
add_host(
host=raw_vsphere_host,
obj_id_prefix='vc',
# icon='icon_topic_hosts',
icon=get_emblem(ICON_VCENTER, params.get(PARAM_VCENTER)),
)
vsphere_host = f'vc{raw_vsphere_host}'
__clusters = {
'HA': {
......@@ -121,7 +142,11 @@ def check_vsphere_topo(
}
if section_esx_vsphere_clusters is None:
yield Result(state=State.UNKNOWN, summary='Found no vSphere data centers/clusters')
yield Result(
state=State.UNKNOWN,
summary='Found no vSphere data centers/clusters. This service needs the "VMware ESX via vSphere" '
'option "Type of query" set to "Queried host is vCenter"'
)
return
for cluster in section_esx_vsphere_clusters:
......@@ -133,7 +158,6 @@ def check_vsphere_topo(
link2core=False,
)
add_connection(data_center, vsphere_host)
add_host(
host=cluster,
emblem=get_emblem(EMBLEM_CLUSTER, params.get(PARAM_CLUSTER)),
......@@ -178,8 +202,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, {}))
if params.get(PARAM_DONT_ADD_VC_AS_VM) is True and vm_name.lower() == vsphere_host.lower():
continue
# 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)
......@@ -232,8 +256,8 @@ 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 params.get(PARAM_DONT_ADD_VC_AS_VM) is True and vm_name.lower() == vsphere_host.lower():
continue
# 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:
......@@ -250,21 +274,30 @@ def check_vsphere_topo(
'version': 1,
'name': 'vSphere',
'objects': dict(sorted(objects.items())),
# 'objects': objects,
'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]
data_sets = []
# workaround for backend is only picking up topologies from default folder
path: str = f'{OMD_ROOT}/var/check_mk/topology/data/default'
if Path(path).exists():
dummy_topology = {'version': 1, 'name': 'vSphere', 'objects': {}, 'connections': []}
save_data_to_file(
data=dummy_topology,
file='data_vsphere.json',
make_default=params.get(PARAM_MAKE_DEFAULT, False),
path=path,
)
for topology in get_topologies():
data_sets.append({'version': 1, 'name': topology, 'objects': {}, 'connections': []})
# end workaround
data_sets.append(data_set_vsphere)
path: str = f'{OMD_ROOT}/var/check_mk/topology/data/{raw_vsphere_host}'
for data_set in data_sets:
file: str = f'data_{data_set["name"].lower()}.json'
save_data_to_file(
......
......@@ -8,8 +8,8 @@
# 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 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
......@@ -20,6 +20,8 @@ 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'
......@@ -38,6 +40,10 @@ PARAM_NO_EMBLEM: Final[str] = 'no_emblem'
PARAM_PREFIX: Final[str] = 'prefix'
PARAM_UPPER: Final[str] = 'upper'
PARAM_VM_NAMES: Final[str] = 'vm_names'
PARAM_VCENTER: Final[str] = 'vcenter_icon'
PICTURE_TYPE_EMBLEM: Final[str] = 'emblem'
PICTURE_TYPE_ICON: Final[str] = 'icon'
RULE_SET_NAME_VSPHERE_TOPO: Final[str] = 'vsphere_topo'
......@@ -110,6 +116,17 @@ def save_data_to_file(data: Mapping, path: str, file: str, make_default: bool) -
Path(f'{parent_path}/default').symlink_to(target=Path(path), target_is_directory=True)
def get_topologies() -> Sequence[str | None]:
path: str = f'{OMD_ROOT}/var/check_mk/topology/data/default'
if not Path(path).exists():
return []
files = [f for f in Path(path).glob('*.json') if f.is_file()]
return [
json_loads(Path(file).read_text()).get('name') for file in files if
json_loads(Path(file).read_text()).get('name') is not None
]
#
# live status
#
......
......@@ -48,6 +48,10 @@ from cmk_addons.plugins.vsphere_topo.lib.utils import (
PARAM_UPPER,
PARAM_VM_NAMES,
RULE_SET_NAME_VSPHERE_TOPO,
PARAM_VCENTER,
ICON_VCENTER,
PICTURE_TYPE_EMBLEM,
PICTURE_TYPE_ICON,
)
adjust_names_elements: Mapping[str, DictElement] = {
......@@ -75,25 +79,25 @@ adjust_names_elements: Mapping[str, DictElement] = {
}
def get_emblem_element(default_emblem) -> Sequence[CascadingSingleChoiceElement]:
def get_emblem_element(default_emblem: str, picture_type: str) -> Sequence[CascadingSingleChoiceElement]:
return [
CascadingSingleChoiceElement(
name=PARAM_NO_EMBLEM,
title=Title('No custom emblem'),
title=Title(f'No custom {picture_type}'),
parameter_form=FixedValue(
value=True,
label=Label('No custom emblem will be used')
label=Label(f'No custom {picture_type} will be used')
)),
CascadingSingleChoiceElement(
name=PARAM_DEFAULT_EMBLEM,
title=Title('Use default emblem'),
title=Title(f'Use default {picture_type}'),
parameter_form=FixedValue(
value=True,
label=Label(f'Emblem "{default_emblem}" will be used')
label=Label(f'"{default_emblem}" will be used as {picture_type}')
)),
CascadingSingleChoiceElement(
name=PARAM_CUSTOM_EMBLEM,
title=Title('Use custom emblem'),
title=Title(f'Use custom {picture_type}'),
parameter_form=String(
custom_validate=(LengthInRange(min_value=1),),
prefill=DefaultValue(default_emblem),
......@@ -114,10 +118,20 @@ def _parameter_form() -> Dictionary:
title=Title('Adjust VM names'),
elements=adjust_names_elements
)),
PARAM_VCENTER: DictElement(
parameter_form=CascadingSingleChoice(
title=Title('vCenter Icon'),
elements=get_emblem_element(ICON_VCENTER, PICTURE_TYPE_ICON),
prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
help_text=Help(
'Here you can change the icon for the vCenter object. If you use the built-in icons prefix '
'the name with "icon_"'
),
)),
PARAM_CLUSTER: DictElement(
parameter_form=CascadingSingleChoice(
title=Title('Cluster emblem'),
elements=get_emblem_element(EMBLEM_CLUSTER),
elements=get_emblem_element(EMBLEM_CLUSTER, PICTURE_TYPE_EMBLEM),
prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
help_text=Help(
'Here you can change the picture for the cluster. If you use the built-in icons prefix '
......@@ -127,7 +141,7 @@ def _parameter_form() -> Dictionary:
PARAM_DATA_CENTER: DictElement(
parameter_form=CascadingSingleChoice(
title=Title('Datacenter emblem'),
elements=get_emblem_element(EMBLEM_DATA_CENTER),
elements=get_emblem_element(EMBLEM_DATA_CENTER, PICTURE_TYPE_EMBLEM),
prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
help_text=Help(
'Here you can change the picture for the datacenter. If you use the built-in icons prefix '
......@@ -137,7 +151,7 @@ def _parameter_form() -> Dictionary:
PARAM_DATA_STORE: DictElement(
parameter_form=CascadingSingleChoice(
title=Title('Datastore emblem'),
elements=get_emblem_element(EMBLEM_DATA_STORE),
elements=get_emblem_element(EMBLEM_DATA_STORE, PICTURE_TYPE_EMBLEM),
prefill=DefaultValue(PARAM_DEFAULT_EMBLEM),
help_text=Help(
'Here you can change the picture for the datastore. If you use the built-in icons prefix '
......@@ -165,6 +179,7 @@ def _parameter_form() -> Dictionary:
value=True
)),
PARAM_DONT_ADD_VC_AS_VM: DictElement(
render_only=True,
parameter_form=FixedValue(
title=Title('Don\'t add vCenter as VM'),
label=Label('The vCenter will not be added as VM'),
......@@ -175,6 +190,7 @@ def _parameter_form() -> Dictionary:
value=True
)),
PARAM_ADD_DUMMY_TOPOLOGIES: DictElement(
render_only=True,
parameter_form=FixedValue(
title=Title('Add dummy topologies'),
label=Label('Adds empty CDP, LLDP, L3v4 and STATIC topology'),
......
......@@ -12,7 +12,7 @@
'vsphere_topo/graphing/packages.py']},
'name': 'vsphere_topo',
'title': 'vSphere Topologie',
'version': '0.0.2-20240709',
'version': '0.0.3-20240711',
'version.min_required': '2.3.0b1',
'version.packaged': 'cmk-mkp-tool 0.2.0',
'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