From eb2aa990facf5d8973aece0e594772e5ecbcec7c Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Thu, 11 Jul 2024 21:49:01 +0200
Subject: [PATCH] update project

---
 README.md                                     |   2 +-
 mkp/vsphere_topo-0.0.3-20240711.mkp           | Bin 0 -> 7281 bytes
 .../vsphere_topo/agent_based/packages.py      |  93 ++++++++++++------
 .../vsphere_topo/lib/utils.py                 |  21 +++-
 .../vsphere_topo/rulesets/packages.py         |  34 +++++--
 source/packages/vsphere_topo                  |   2 +-
 6 files changed, 109 insertions(+), 43 deletions(-)
 create mode 100644 mkp/vsphere_topo-0.0.3-20240711.mkp

diff --git a/README.md b/README.md
index d12b93e..53f352c 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[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.
diff --git a/mkp/vsphere_topo-0.0.3-20240711.mkp b/mkp/vsphere_topo-0.0.3-20240711.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..be24721712f3b21055ae229868bc21e987abbc9d
GIT binary patch
literal 7281
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
bT&`60s?q}fzfny3Rm?nhodM=A49x!k)81te

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 401aa8f..8c70ca9 100644
--- a/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py
+++ b/source/cmk_addons_plugins/vsphere_topo/agent_based/packages.py
@@ -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(
diff --git a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py
index f32e717..2e8ca1d 100644
--- a/source/cmk_addons_plugins/vsphere_topo/lib/utils.py
+++ b/source/cmk_addons_plugins/vsphere_topo/lib/utils.py
@@ -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
 #
diff --git a/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py b/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py
index 800fdae..bcbb4e5 100644
--- a/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py
+++ b/source/cmk_addons_plugins/vsphere_topo/rulesets/packages.py
@@ -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'),
diff --git a/source/packages/vsphere_topo b/source/packages/vsphere_topo
index 142ae81..d748247 100644
--- a/source/packages/vsphere_topo
+++ b/source/packages/vsphere_topo
@@ -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'}
-- 
GitLab