From 823004333017b67fbd5b6c07e50b577d1320d042 Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Fri, 27 Sep 2024 13:21:50 +0200
Subject: [PATCH] update project

---
 README.md                          |   2 +-
 mkp/nvdct-0.9.0-20240923.mkp       | Bin 0 -> 39823 bytes
 source/bin/nvdct/conf/nvdct.toml   |  24 ++-
 source/bin/nvdct/lib/args.py       |  58 +++----
 source/bin/nvdct/lib/backends.py   | 127 +++++----------
 source/bin/nvdct/lib/settings.py   | 119 ++++++++------
 source/bin/nvdct/lib/topologies.py |   6 +-
 source/bin/nvdct/lib/utils.py      |   6 +-
 source/bin/nvdct/nvdct.py          | 244 ++++++++++++-----------------
 source/packages/nvdct              |  12 +-
 10 files changed, 271 insertions(+), 327 deletions(-)
 create mode 100644 mkp/nvdct-0.9.0-20240923.mkp

diff --git a/README.md b/README.md
index bbc24b3..e77139d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[PACKAGE]: ../../raw/master/mkp/nvdct-0.8.12-20240702.mkp "nvdct-0.8.12-20240702.mkp"
+[PACKAGE]: ../../raw/master/mkp/nvdct-0.9.0-20240923.mkp "nvdct-0.9.0-20240923.mkp"
 # Network Visualization Data Creation Tool (NVDCT)
 
 This script creates the topology data file needed for the [Checkmk Exchange Network visualization](https://exchange.checkmk.com/p/network-visualization) plugin.\
diff --git a/mkp/nvdct-0.9.0-20240923.mkp b/mkp/nvdct-0.9.0-20240923.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..e7925df7a841b83c72474e9ec4a66687335ad8bf
GIT binary patch
literal 39823
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
L9~XhF0DuAjpO6w~

literal 0
HcmV?d00001

diff --git a/source/bin/nvdct/conf/nvdct.toml b/source/bin/nvdct/conf/nvdct.toml
index ac4235e..48d787b 100755
--- a/source/bin/nvdct/conf/nvdct.toml
+++ b/source/bin/nvdct/conf/nvdct.toml
@@ -84,6 +84,20 @@ CUSTOM_LAYERS = [
 #    { path = "networking,cdp_cache,neighbours", columns = "neighbour_name,local_port,neighbour_port", label = "custom_CDP", host_label = "nvdct/has_cdp_neighbours" },
 ]
 
+# list site so include/excluse, use option --filter-sites INCLUDE/EXCLUDE 
+SITES = [
+    # "site1",
+    # "site2",
+    # "site3",
+]
+
+# list customers so include/excluse, use option --filter-costumers INCLUDE/EXCLUDE 
+CUSTOMERS = [
+    # "customer1",
+    # "customer2",
+    # "customer3",
+]
+
 [MAP_SPEED_TO_THICKNESS]
 # must be sorted from slower to faster speed
 # use only one entry to have all conections with the same thickness
@@ -122,23 +136,23 @@ CUSTOM_LAYERS = [
 
 [SETTINGS]
 # api_port = 80
-# backend = "MULTISITE"
+# backend = "MULTISITE" | "RESTAPI" | "LIVESTATUS"
+# case = "LOWER" | "UPPER"
 # default = false
 # dont_compare = false
+# filter_customers = "INCLUDE" |"EXCLUDE"
+# filter_sites = "INCLUDE" | "EXCLUDE"
 # keep = 0
 # keep_domain = false
 # layers = ["LLDP", "CDP", "STATIC", "CUSTOM", "L3v4"]
 # log_file = "~/var/log/nvdct.log"
 # log_level = "WARNING"
 # log_to_stdout = false
-# lowercase = false
 # min_age = 0
-# new_format = false
 # output_directory = ''
-# prefix = ""
 # pre_fetch = false
+# prefix = ""
 # quiet = true
 # skip_l3_if = false
 # skip_l3_ip = false
 # time_format = "%Y-%m-%dT%H:%M:%S.%m"
-# uppercase = false
diff --git a/source/bin/nvdct/lib/args.py b/source/bin/nvdct/lib/args.py
index 9376073..080a075 100755
--- a/source/bin/nvdct/lib/args.py
+++ b/source/bin/nvdct/lib/args.py
@@ -18,22 +18,22 @@
 # -u --user-data-file
 # -v --version
 # --api-port (deprecated ?)
+# --case
 # --check-user-data-only
 # --dont-compare
+# --filter-customers
+# --filter-sites
 # --keep
 # --keep-domain
 # --log-file
 # --log-level
 # --log-to-stdout
-# --lowercase
 # --min-age
-# --new-format (deprecated)
 # --pre-fetch
 # --quiet
 # --skip-l3-if
 # --skip-l3-ip
 # --time-format
-# --uppercase
 
 
 from argparse import (
@@ -41,6 +41,8 @@ from argparse import (
     Namespace as arg_Namespace,
     RawTextHelpFormatter,
 )
+from pathlib import Path
+
 from lib.utils import (
     ExitCodes,
     HOME_URL,
@@ -83,15 +85,12 @@ def parse_arguments() -> arg_Namespace:
                '\nUsage:\n'
                f'{SCRIPT} -s {SAMPLE_SEEDS} -d\n\n'
     )
-    command_group = parser.add_mutually_exclusive_group()
 
     parser.add_argument(
         '-b', '--backend',
-        # nargs='+',
-        choices=['FILESYSTEM', 'LIVESTATUS', 'MULTISITE', 'RESTAPI'],
+        choices=['LIVESTATUS', 'MULTISITE', 'RESTAPI'],
         # default='MULTISITE',
         help='Backend used to retrieve the topology data\n'
-             ' - FILESYSTEM : fetches the data directly form the inventory files (deprecatred)\n'
              ' - LIVESTATUS : fetches data via local Livestatus (local site only)\n'
              ' - MULTISITE  : like LIVESTATUS but for distributed environments (default)\n'
              ' - RESTAPI    : uses the CMK REST API.',
@@ -101,14 +100,12 @@ def parse_arguments() -> arg_Namespace:
         help='Set the created topology data as default. Will be created automatically\n'
              'if it doesn\'t exists.',
     )
-
     parser.add_argument(
         '-o', '--output-directory', type=str,
         help='Directory name where to save the topology data.\n'
              'I.e.: my_topology. Default is the actual date/time\n'
              'in "--time-format" format.\n'
-             'NOTE: the directory is a sub directory under "~/var/topology_data/" (CMK2.2.0)\n'
-             'For CMK 2.3.0 the path is under "~/var/check_mk/topology/data/".',
+             'NOTE: the directory is a sub directory under "~/var/check_mk/topology/data/"\n',
     )
     parser.add_argument(
         '-s', '--seed-devices', type=str, nargs='+',
@@ -125,12 +122,10 @@ def parse_arguments() -> arg_Namespace:
         choices=['CDP', 'CUSTOM', 'LLDP', 'STATIC', 'L3v4'],
         # default=['CDP'],
         help=(
-            f'Layers with least significant layer first. Listed layers\n'
-            f'will be merged automatically (CMK2.2 only).\n'
             f' - CDP  : needs inv_cdp_cache package at least in version {MIN_CDP_VERSION}\n'
             f' - LLDP : needs inv_lldp_cache package at least in version {MIN_LLDP_VERSION}\n'
             f' - L3v4 : needs inv_ipv4_addresses package at least in version {MIN_IPV4_ADDRESSES}\n'
-            f'          adds, layer 3 topology fpr IPv4 (CMK 2.3.0 only)'
+            f'          adds, layer 3 topology fpr IPv4 '
         )
     )
     parser.add_argument(
@@ -139,7 +134,8 @@ def parse_arguments() -> arg_Namespace:
              f'Default is ~/local/bin/nvdct/conf/conf/{USER_DATA_FILE}\n',
     )
     parser.add_argument(
-        '-v', '--version', action='store_const', const=True,  # default=False,
+        '-v', '--version', action='version',
+        version=f'{Path(SCRIPT).name} version: {NVDCT_VERSION}',
         help='Print version of this script and exit',
     )
     parser.add_argument(
@@ -147,6 +143,12 @@ def parse_arguments() -> arg_Namespace:
         help='TCP Port to access the REST API. Default is 80. NVDCT will try to automatically\n'
              'detect the site apache port.',
     )
+    parser.add_argument(
+        '--case',
+        choices=['LOWER', 'UPPER'],
+        # default='NONE',
+        help='Change neighbour name to all lower/upper case',
+    )
     parser.add_argument(
         '--check-user-data-only', action='store_const', const=True,  # default=False,
         help=f'Only tries to read/parse the user data from {USER_DATA_FILE} and exits.',
@@ -174,6 +176,20 @@ def parse_arguments() -> arg_Namespace:
              'So, if you run this tool in a cron job, a new topology will be\n'
              'created only if there was a change, unless you use "--dont-compare".'
     )
+    parser.add_argument(
+        '--filter-customers',
+        choices=['INCLUDE', 'EXCLUDE'],
+        # default='INCLUDE',
+        help='INCLUDE/EXCLUDE customer list from config file.\n'
+             'Note: MULTISITE backend only.',
+    )
+    parser.add_argument(
+        '--filter-sites',
+        choices=['INCLUDE', 'EXCLUDE'],
+        # default='INCLUDE',
+        help='INCLUDE/EXCLUDE site list from config file.\n'
+             'Note: MULTISITE backend only.',
+    )
     parser.add_argument(
         '--keep-domain', action='store_const', const=True,  # default=False,
         help='Do not remove the domain name from the neighbor name',
@@ -184,19 +200,10 @@ def parse_arguments() -> arg_Namespace:
              'max will be deleted.\n'
              'NOTE: The default topologies will be always kept.\n'
     )
-    command_group.add_argument(
-        '--lowercase', action='store_const', const=True,  # default=False,
-        help='Change neighbour names to all lower case',
-    )
     parser.add_argument(
         '--min-age', type=int,
         help='The minimum number of days before a topology is deleted by "--keep".'
     )
-    parser.add_argument(
-        '--new-format', action='store_const', const=True,  # default=False,
-        help='Save data in new format. Use for CMK 2.3.x\n'
-             'NVDCT will try to automatically detect the correct format. (deprecated)',
-    )
     parser.add_argument(
         '--pre-fetch', action='store_const', const=True,  # default=False,
         help='Try to fetch host data, with less API calls. Can improve RESTAPI backend\n'
@@ -218,8 +225,5 @@ def parse_arguments() -> arg_Namespace:
         '--time-format', type=str,
         help=f'Format string to render the time. (default: {TIME_FORMAT_ARGPARSER})',
     )
-    command_group.add_argument(
-        '--uppercase', action='store_const', const=True,  # default=False,
-        help='Change neighbour names to all upper case',
-    )
+
     return parser.parse_args()
diff --git a/source/bin/nvdct/lib/backends.py b/source/bin/nvdct/lib/backends.py
index bfccbb2..6d003fd 100755
--- a/source/bin/nvdct/lib/backends.py
+++ b/source/bin/nvdct/lib/backends.py
@@ -10,7 +10,7 @@
 
 # 2024-06-18: fixed host_exist returns always True if host was in host_cache, even with host=None
 
-from _collections_abc import Mapping, Sequence
+from collections.abc import Mapping, Sequence
 from abc import abstractmethod
 from ast import literal_eval
 from enum import Enum, unique
@@ -334,10 +334,19 @@ class HostCacheLiveStatus(HostCache):
 
 
 class HostCacheMultiSite(HostCacheLiveStatus):
-    def __init__(self, pre_fetch: bool):
+    def __init__(
+        self,
+        pre_fetch: bool,
+        filter_sites: str | None = None,
+        sites: List[str] = [],
+        filter_customers: str | None = None,
+        customers: List[str] = None,
+    ):
         self._backend = '[MULTISITE]'
         self.sites: SiteConfigurations = SiteConfigurations({})
         self.get_sites()
+        self.filter_sites(filter_sites, sites)
+        self.filter_costumers(filter_customers, customers)
         LOGGER.info(f'{self.backend} Create livestatus connection(s)')
         self.c = MultiSiteConnection(self.sites)
         # self.c.set_prepend_site(False)  # is default
@@ -351,9 +360,8 @@ class HostCacheMultiSite(HostCacheLiveStatus):
         if self.pre_fetch:
             self.pre_fetch_hosts()
 
+    # https://github.com/Checkmk/checkmk/blob/master/packages/cmk-livestatus-client/example_multisite.py
     def get_sites(self):
-        # see: https://github.com/Checkmk/checkmk/blob/master/packages/cmk-livestatus-client/example_multisite.py
-
         sites_mk = Path(f'{OMD_ROOT}/etc/check_mk/multisite.d/sites.mk')
         socket_path = f'unix:{OMD_ROOT}/tmp/run/live'
         if sites_mk.exists():
@@ -372,6 +380,7 @@ class HostCacheMultiSite(HostCacheLiveStatus):
                 self.sites.update({site: {
                     'alias': data['alias'],
                     'timeout': data['timeout'],
+                    'customer': data['customer']  # needed to filter by customer
                     # 'nagios_url': '/nagios/',
                 }})
                 if data['socket'] == ('local', None):
@@ -395,10 +404,32 @@ class HostCacheMultiSite(HostCacheLiveStatus):
             }})
 
             LOGGER.critical(
-                f'{self.backend} file {str(sites_mk.absolute())} not found. Fallback to'
+                f'{self.backend} file {str(sites_mk.absolute())} not found. Fallback to '
                 'local site only. Try -b RESTAPI if you have a distributed environment.'
             )
 
+    def filter_sites(self, filter: str| None, sites:List[str]):
+        match filter:
+            case 'INCLUDE':
+                self.sites = {site: data for site, data in self.sites.items() if site in sites}
+            case 'EXCLUDE':
+                self.sites = {site: data for site, data in self.sites.items() if site not in sites}
+            case _:
+                return
+
+    def filter_costumers(self, filter: str | None, costumers:List[str]):
+        match filter:
+            case 'INCLUDE':
+                self.sites = {
+                    site: data for site, data in self.sites.items() if data.get('customer') in costumers
+                }
+            case 'EXCLUDE':
+                self.sites = {
+                    site: data for site, data in self.sites.items() if data.get('customer') not in costumers
+                }
+            case _:
+                return
+
     def get_raw_data(self, query: str) -> object:
         return self.c.query(query=query)
 
@@ -589,89 +620,3 @@ class HostCacheRestApi(HostCache):
             LOGGER.debug(f'{self.backend} # of host found: {len(self.cache.keys())}')
         else:
             LOGGER.warning(f'{self.backend} respons: {resp.text}')
-
-
-class HostCacheFileSystem(HostCache):
-    def __init__(self, pre_fetch: bool):
-        super().__init__(pre_fetch, '[FILESYSTEM]')
-
-    def get_inventory_data(self, hosts: Sequence[str]) -> Dict[str, Dict | None]:
-        host_data: Dict[str, Dict | None] = {}
-        __inventory_path = 'var/check_mk/inventory'
-        for host in hosts:
-            # init host_data with None
-            host_data[host] = None
-            inventory_file: Path = Path(f'{OMD_ROOT}/{__inventory_path}/{host}')
-            try:
-                data = literal_eval(inventory_file.read_text())
-            except FileNotFoundError:
-                LOGGER.warning(
-                    msg=f'{self.backend} Device: {host}: not found in inventory data path!'
-                )
-                continue
-
-            LOGGER.debug(f'{self.backend} data for host {host}: {data}')
-            host_data[host] = data
-
-        return host_data
-
-    def get_interface_data(self, hosts: Sequence[str]) -> Dict[str, Dict | None]:
-        """
-        Sample autochecks data, we keep only the item
-        [
-         {'check_plugin_name': 'if64', 'item': 'Fa0', 'parameters': {'discovered_oper_status': ['2'], ...}},\n  # noqa: E501
-         {'check_plugin_name': 'if64', 'item': 'Fa1/0/1', 'parameters': {'discovered_oper_status': ['1'], ...}},\n  # noqa: E501
-         {'check_plugin_name': 'if64', 'item': 'Fa1/0/10', 'parameters': {'discovered_oper_status': ['2'], ...}},\n  # noqa: E501
-         {'check_plugin_name': 'if64', 'item': 'Fa1/0/11', 'parameters': {'discovered_oper_status': ['2'], ...}},\n  # noqa: E501
-         {'check_plugin_name': 'if64', 'item': 'Fa1/0/12', 'parameters': {'discovered_oper_status': ['1'], ...}}\n  # noqa: E501
-        ]
-
-        Args:
-            hosts: list of names of the host objects in cmk to fetch the data for
-
-        Returns:
-            List of interface service items
-
-        """
-        host_data: Dict[str, Dict | None] = {}
-        __autochecks_path = 'var/check_mk/autochecks'
-        for host in hosts:
-            # init host_data with None
-            host_data[host] = None
-            autochecks_file: Path = Path(f'{OMD_ROOT}/{__autochecks_path}/{host}.mk')
-            items: Dict[str, object] = {}
-            try:
-                data: Sequence[Mapping[str, str]] = literal_eval(autochecks_file.read_text())
-            except FileNotFoundError:
-                LOGGER.warning(
-                    msg=f'{self.backend} Device: {host}: not found in auto checks path!'
-                )
-                continue
-            LOGGER.debug(f'{self.backend} data for host {host}: {data}')
-
-            for service in data:
-                if service['check_plugin_name'] in ['if64']:
-                    items[service['item']] = {}
-
-            if items:
-                LOGGER.info(
-                    msg=f'{self.backend} Interfaces items found: {len(items)} an host {host}'
-                )
-                host_data[host] = items
-            else:
-                LOGGER.warning(
-                    msg=f'{self.backend} No Interfaces items found for host {host}'
-                )
-        return host_data
-
-    def host_exists(self, host: str) -> bool:
-        # always True, don't works in distributed environments as autocheck files
-        # are only locally available
-        return False
-
-    def get_hosts_by_label(self, label: str) -> List[str] | None:
-        # not implemented, no (good) way to get a list of hosts from file system
-        return None
-
-    def pre_fetch_hosts(self):
-        pass
diff --git a/source/bin/nvdct/lib/settings.py b/source/bin/nvdct/lib/settings.py
index 610abdc..8a55f55 100755
--- a/source/bin/nvdct/lib/settings.py
+++ b/source/bin/nvdct/lib/settings.py
@@ -10,11 +10,10 @@
 
 # fixed path to default user data file
 
-from _collections_abc import Mapping
+from collections.abc import Mapping
 from ipaddress import AddressValueError, IPv4Address, IPv4Network, NetmaskValueError
 from logging import CRITICAL, FATAL, ERROR, WARNING, INFO, DEBUG
 from os import environ
-from pathlib import Path
 from sys import exit as sys_exit
 from time import strftime
 from typing import Dict, List, NamedTuple
@@ -23,10 +22,8 @@ from lib.utils import (
     ExitCodes,
     get_data_from_toml,
     get_local_cmk_api_port,
-    get_local_cmk_version,
+    # get_local_cmk_version,
     LOGGER,
-    NVDCT_VERSION,
-    SCRIPT,
     TIME_FORMAT,
     USER_DATA_FILE,
     Layer
@@ -71,24 +68,25 @@ class Settings:
         self.__omd_root = environ['OMD_ROOT']
         self.__path_to_if_table = 'networking,interfaces'
         self.__topology_file_name = 'network_data.json'
-        self.__topology_save_path = 'var/topology_data'
+        # self.__topology_save_path = 'var/topology_data'
         self.__topology_save_path_cmk_2_3 = 'var/check_mk/topology/data'
         # cli defaults
         self.__settings = {
             # 'api_port': 80,
             'backend': 'MULTISITE',
+            'case': None,
             'check_user_data_only': False,
             'default': False,
             'dont_compare': False,
+            'filter_customers': None,
+            'filter_sites': None,
             'keep': False,
             'keep_domain': False,
             'layers': ['CDP'],
             'log_file': f'{self.omd_root}/var/log/nvdct.log',
             'log_level': 'WARNING',
             'log_to_stdout': False,
-            'lowercase': False,
             'min_age': 0,
-            # 'new_format': False,
             'output_directory': None,
             'prefix': None,
             'quiet': False,
@@ -97,9 +95,8 @@ class Settings:
             'skip_l3_if': False,
             'skip_l3_ip': False,
             'time_format': TIME_FORMAT,
-            'uppercase': False,
             'user_data_file': f'{self.omd_root}/local/bin/nvdct/conf/{USER_DATA_FILE}',
-            'version': False,
+            # 'version': False,
         }
         # args in the form {'s, __seed_devices': 'CORE01', 'p, __path_in_inventory': None, ... }}
         # we will remove 's, __'
@@ -107,10 +104,6 @@ class Settings:
             {k.split(',')[-1].strip(' ').strip('_'): v for k, v in cli_args.items() if v}
         )
 
-        if self.__args.get('version'):
-            print(f'{Path(SCRIPT).name} version: {NVDCT_VERSION}')
-            sys_exit(ExitCodes.OK.value)
-
         self.__user_data = get_data_from_toml(
             file=self.__args.get('user_data_file', self.user_data_file)
         )
@@ -134,7 +127,6 @@ class Settings:
                 sys_exit(ExitCodes.BAD_OPTION_LIST.value)
 
         self.__api_port: int | None = None
-        self.__new_format: bool | None = None
 
         # init user data with defaults
         self.__custom_layers: List[StaticConnection] | None = None
@@ -151,6 +143,8 @@ class Settings:
         self.__seed_devices: List[str] | None = None
         self.__static_connections: List[StaticConnection] | None = None
         self.__emblems: Emblems | None = None
+        self.__sites: List[str] | None = None
+        self.__customers: List[str] | None = None
 
     #
     # CLI settings
@@ -169,7 +163,25 @@ class Settings:
 
     @property  # -b --backend
     def backend(self) -> str:
-        return str(self.__settings['backend'])
+        if str(self.__settings['backend']) in ['LIVESTATUS', 'MULTISITE', 'RESTAPI']:
+            return str(self.__settings['backend'])
+        else:  # fallback to defaukt -> exit ??
+            LOGGER.warning(
+                f'Unknown backend: {self.__settings['backend']}. Accepted backends are: '
+                'LIVESTATUS, MULTISITE, RESTAPI. Fall back zo MULTISITE.'
+            )
+            return 'MULTISITE'
+
+    @property  # --case
+    def case(self) -> str| None:
+        if self.__settings['case'] in ['LOWER', 'UPPER']:
+            return self.__settings['case']
+        elif self.__settings['case'] is not None:
+            LOGGER.warning(
+                    f'Unknon case setting {self.__settings["case"]}. '
+                    'Accepted are LOWER|UPPER. Fallback to no change.'
+                )
+        return None
 
     @property  # --check-user-data-only
     def check_user_data_only(self) -> bool:
@@ -183,6 +195,28 @@ class Settings:
     def dont_compare(self) -> bool:
         return bool(self.__settings['dont_compare'])
 
+    @property  # --filter-customers
+    def filter_customers(self) -> str | None:
+        if self.__settings['filter_customers'] in ['INCLUDE', 'EXCLUDE']:
+            return self.__settings['filter_customers']
+        elif self.__settings['filter_customers'] is not None:
+            LOGGER.error(
+                f'Wrong setting for "filter_customers": '
+                f'{self.__settings["filter_customers"]}, supported settings INCLUDE|EXCLUDE.'
+            )
+        return None
+
+    @property  # --filter-sites
+    def filter_sites(self) -> str | None:
+        if self.__settings['filter_sites'] in ['INCLUDE', 'EXCLUDE']:
+            return self.__settings['filter_sites']
+        elif self.__settings['filter_sites'] is not None:
+            LOGGER.error(
+                f'Wrong setting for "filter_sites": '
+                f'{self.__settings["filter_sites"]}, supported settings INCLUDE|EXCLUDE.'
+            )
+        return None
+
     @property  # --keep
     def keep(self) -> int | None:
         if isinstance(self.__settings['keep'], int):
@@ -225,10 +259,6 @@ class Settings:
     def log_to_stdtout(self) -> bool:
         return bool(self.__settings['log_to_stdout'])
 
-    @property  # --lowercase
-    def lowercase(self) -> bool:
-        return bool(self.__settings['lowercase'])
-
     @property  # --min-age
     def min_age(self) -> int:
         if isinstance(self.__settings['min_age'], int):
@@ -236,18 +266,6 @@ class Settings:
         else:
             return 0
 
-    @property  # --new-format
-    def new_format(self) -> bool:
-        if self.__new_format is None:
-            if self.__settings.get('new_format') is True:
-                self.__new_format = True
-            elif get_local_cmk_version().startswith('2.2'):
-                self.__new_format = False
-            else:
-                self.__new_format = True
-
-        return self.__new_format
-
     @property  # --output-directory
     def output_directory(self) -> str:
         # init output directory with current time if not set
@@ -289,17 +307,13 @@ class Settings:
     def time_format(self) -> str:
         return str(self.__settings['time_format'])
 
-    @property  # --uppercase
-    def uppercase(self) -> bool:
-        return bool(self.__settings['uppercase'])
-
     @property  # --user-data-file
     def user_data_file(self) -> str:
         return str(self.__settings['user_data_file'])
 
-    @property  # --version
-    def version(self) -> bool:
-        return bool(self.__settings['version'])
+    # @property  # --version
+    # def version(self) -> bool:
+    #     return bool(self.__settings['version'])
 
     #
     #  user data setting
@@ -330,7 +344,7 @@ class Settings:
     @property
     def drop_hosts(self) -> List[str]:
         if self.__drop_host is None:
-            self.__drop_host = [str(host) for host in self.__user_data.get('DROP_HOSTS', [])]
+            self.__drop_host = [str(host) for host in set(self.__user_data.get('DROP_HOSTS', []))]
         return self.__drop_host
 
     @property
@@ -368,9 +382,9 @@ class Settings:
     @property
     def l3v4_ignore_hosts(self) -> List[str]:
         if self.__l3v4_ignore_hosts is None:
-            self.__l3v4_ignore_hosts = [str(host) for host in self.__user_data.get(
+            self.__l3v4_ignore_hosts = [str(host) for host in set(self.__user_data.get(
                 'L3V4_IGNORE_HOSTS', []
-            )]
+            ))]
         return self.__l3v4_ignore_hosts
 
     @property
@@ -523,6 +537,22 @@ class Settings:
             )
         return self.__static_connections
 
+    @property
+    def sites(self) -> List[str]:
+        if self.__sites is None:
+            self.__sites = [str(site) for site in set(self.__user_data.get('SITES', []))]
+            LOGGER.info(f'fFound {len(self.__sites)} to filter on')
+        return self.__sites
+
+    @property
+    def customers(self) -> List[str]:
+        if self.__customers is None:
+            self.__customers = [
+                str(customer) for customer in set(self.__user_data.get('CUSTOMERS', []))
+            ]
+            LOGGER.info(f'fFound {len(self.__customers)} to filter on')
+        return self.__customers
+
     #
     # all other settings
     #
@@ -532,10 +562,7 @@ class Settings:
 
     @property
     def topology_save_path(self) -> str:
-        if self.new_format:
-            return self.__topology_save_path_cmk_2_3
-
-        return self.__topology_save_path
+        return self.__topology_save_path_cmk_2_3
 
     @property
     def topology_file_name(self) -> str:
diff --git a/source/bin/nvdct/lib/topologies.py b/source/bin/nvdct/lib/topologies.py
index 712fb33..8c35a45 100755
--- a/source/bin/nvdct/lib/topologies.py
+++ b/source/bin/nvdct/lib/topologies.py
@@ -8,7 +8,7 @@
 # Date  : 2024-06-09
 # File  : lib/topologies.py
 
-from _collections_abc import Mapping, Sequence
+from collections.abc import Mapping, Sequence
 from ipaddress import IPv4Address, IPv4Network
 from typing import Dict, List
 
@@ -20,6 +20,8 @@ from lib.utils import LOGGER
 class NvObjects:
     def __init__(self) -> None:
         self.nv_objects: Dict[str, any] = {}
+        self.host_count: int = 0
+        self.host_list: List[str] = []
 
     def add_host_object(
         self,
@@ -28,6 +30,8 @@ class NvObjects:
         emblem: str | None = None
     ) -> None:
         if host not in self.nv_objects:
+            self.host_count += 1
+            self.host_list.append(host)
             link: Dict = {}
             metadata: Dict = {}
             # LOGGER.debug(f'host: {host}, {host_cache.host_exists(host=host)}')
diff --git a/source/bin/nvdct/lib/utils.py b/source/bin/nvdct/lib/utils.py
index 572fb9e..d92a87d 100755
--- a/source/bin/nvdct/lib/utils.py
+++ b/source/bin/nvdct/lib/utils.py
@@ -7,7 +7,7 @@
 # Date  : 2023-10-12
 # File  : nvdct/lib/utils.py
 
-from _collections_abc import Mapping, Sequence
+from collections.abc import Mapping, Sequence
 from ast import literal_eval
 from dataclasses import dataclass
 from enum import Enum, unique
@@ -23,7 +23,7 @@ from time import time as now_time
 from tomllib import loads as toml_loads, TOMLDecodeError
 from typing import List, Dict, TextIO
 
-NVDCT_VERSION = '0.8.12-20240702'
+NVDCT_VERSION = '0.9.0-20240923'
 
 
 @unique
@@ -251,6 +251,7 @@ 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)
 
 
+# CMK version 2.2.x format
 def save_topology(
         data: dict,
         base_directory: str,
@@ -322,6 +323,7 @@ def is_list_of_str_equal(list1: List[str], list2: List[str]) -> bool:
     return tmp_list1 == tmp_list2
 
 
+# not used in cmk 2.3.x format
 def merge_topologies(topo_pri: Dict, topo_sec: Dict) -> Dict:
     """
     Merge dict_prim into dict_sec
diff --git a/source/bin/nvdct/nvdct.py b/source/bin/nvdct/nvdct.py
index 39c334a..12eda3b 100755
--- a/source/bin/nvdct/nvdct.py
+++ b/source/bin/nvdct/nvdct.py
@@ -113,6 +113,12 @@
 #             moved (default) config file(s) to ./conf/
 # 2024-06-14: added debug code for bad IPv4 address data
 # 2024-06-17: fixed bad IPv4 address data (just drop it)
+# 2024-09-23: replaced options --lowercase/--uppercase with --case LOWER|UPPER
+#             changed version output from settings to argparse action
+#             removed backend FILESYSTEM -> will fallback to MULTISITE
+#             removed support for CMK2.2.x file format (removed option --new-format)
+# 2024-09-24: added site filter for multisite deployments (MULTISITE only), option --filter-sites and SITES section in toml file
+#             added customer filter for MSP deployments (MULTISITE only), option --filter-customers and section CUSTOMERS in toml file
 
 # creating topology data json from inventory data
 #
@@ -208,7 +214,7 @@ __data = {
 """
 
 import sys
-from _collections_abc import Mapping, Sequence
+from collections.abc import Mapping, Sequence
 from ipaddress import IPv4Network
 from logging import DEBUG
 from re import compile as re_compile
@@ -219,7 +225,6 @@ from lib.args import parse_arguments
 from lib.backends import (
     CacheItems,
     HostCache,
-    HostCacheFileSystem,
     HostCacheLiveStatus,
     HostCacheMultiSite,
     HostCacheRestApi,
@@ -227,7 +232,7 @@ from lib.backends import (
 from lib.topologies import (
     NvConnections,
     NvObjects,
-    get_list_of_devices,
+    # get_list_of_devices,
     get_network_summary,
     get_service_by_interface,
     is_ignore_ipv4,
@@ -243,12 +248,12 @@ from lib.utils import (
     Layer,
     LAYERS,
     LOGGER,
-    merge_topologies,
+    # merge_topologies,
     NVDCT_VERSION,
     PATH_L3v4,
     remove_old_data,
     save_data_to_file,
-    save_topology,
+    # save_topology,
     StdoutQuiet,
 )
 from lib.settings import (
@@ -276,9 +281,7 @@ def create_l2_device_from_inv(
         inv_data: Sequence[Mapping[str, str]],
         inv_columns: InventoryColumns,
         label: str,
-) -> Dict[str, object] | None:
-    data: Dict = {'connections': {}, "interfaces": []}
-
+) -> None:
     for topo_neighbour in inv_data:
         # check if required data are not empty
         if not (neighbour := topo_neighbour.get(inv_columns.neighbour)):
@@ -311,10 +314,13 @@ def create_l2_device_from_inv(
             LOGGER.info(msg=f'drop neighbour: {neighbour}')
             continue
 
-        if SETTINGS.uppercase:
+        if SETTINGS.case == 'UPPER':
             neighbour = neighbour.upper()
-        if SETTINGS.lowercase:
+            LOGGER.debug(f'Changed neighbour to upper case: {neighbour}')
+        elif SETTINGS.case == 'LOWER':
             neighbour = neighbour.lower()
+            LOGGER.debug(f'Changed neighbour to lower case: {neighbour}')
+
         if SETTINGS.prefix:
             neighbour = f'{SETTINGS.prefix}{neighbour}'
         # rewrite neighbour if inventory neighbour and checkmk host don't match
@@ -346,17 +352,11 @@ def create_l2_device_from_inv(
                     f'-> neighbour_port {neighbour_port}'
             )
 
-        if neighbour and local_port and neighbour_port:
-            data['connections'].update({local_port: [neighbour, neighbour_port, label]})
-            if local_port not in data['interfaces']:
-                data['interfaces'].append(local_port)
-
         metadata = {
             'duplex': topo_neighbour.get('duplex'),
             'native_vlan': topo_neighbour.get('native_vlan'),
         }
 
-        # add to new object list
         NV_OBJECTS.add_host_object(host=host, host_cache=HOST_CACHE)
         NV_OBJECTS.add_host_object(host=neighbour, host_cache=HOST_CACHE)
         NV_OBJECTS.add_service_object(
@@ -387,32 +387,10 @@ def create_l2_device_from_inv(
             right=f'{neighbour_port}@{neighbour}',
         )
 
-    return {host: data}
-
 
-def create_static_connections(connections: Sequence[StaticConnection]) -> Dict:
-    data: Dict = {}
+def create_static_connections(connections: Sequence[StaticConnection]):
     for connection in connections:
         LOGGER.info(msg=f'connection: {connection}')
-        if connection.host not in data:
-            data[connection.host] = {'connections': {}, 'interfaces': []}
-
-        if connection.neighbour not in data:
-            data[connection.neighbour] = {'connections': {}, 'interfaces': []}
-
-        # add connection from host to neighbour
-        data[connection.host]['connections'].update({connection.local_port: [
-            connection.neighbour, connection.neighbour_port, connection.label
-        ]})
-        data[connection.host]['interfaces'].append(connection.local_port)
-
-        # add connection from neighbour to host
-        data[connection.neighbour]['connections'].update({
-            connection.neighbour_port: [connection.host, connection.local_port, connection.label]
-        })
-        data[connection.neighbour]['interfaces'].append(connection.neighbour_port)
-
-        # new format
         NV_OBJECTS.add_host_object(
             host=connection.host,
             host_cache=HOST_CACHE,
@@ -448,22 +426,14 @@ def create_static_connections(connections: Sequence[StaticConnection]) -> Dict:
             right=f'{connection.neighbour_port}@{connection.neighbour}',
         )
 
-    LOGGER.debug(msg=data)
-    LOGGER.info(msg=f'Devices added: {len(data)}, source STATIC')
-    # if not SETTINGS.quiet:
-    print(f'Devices added.: {len(data)}, source STATIC')
-
-    return data
-
 
 def create_l2_topology(
         seed_devices: Sequence[str],
         path_in_inventory: str,
         inv_columns: InventoryColumns,
         label: str,
-) -> Dict:
+) -> None:
     devices_to_go = list(set(seed_devices))  # remove duplicates
-    topology_data: Dict = {}
     devices_done = []
 
     while devices_to_go:
@@ -482,15 +452,14 @@ def create_l2_topology(
             host=device, item=CacheItems.inventory, path=path_in_inventory
         )
         if topo_data:
-            topology_data.update(
-                create_l2_device_from_inv(
-                    host=device,
-                    inv_data=topo_data,
-                    inv_columns=inv_columns,
-                    label=label,
-                ))
-            devices_list = get_list_of_devices(topology_data[device]['connections'])
-            for _entry in devices_list:
+            create_l2_device_from_inv(
+                host=device,
+                inv_data=topo_data,
+                inv_columns=inv_columns,
+                label=label,
+            )
+
+            for _entry in NV_OBJECTS.host_list:
                 if _entry not in devices_done:
                     devices_to_go.append(_entry)
 
@@ -499,12 +468,6 @@ def create_l2_topology(
         devices_to_go.remove(device)
         LOGGER.info(msg=f'Device done: {device}, source: {label}')
 
-    LOGGER.info(f'Devices added: {len(devices_done)}, source {label}')
-    # if not SETTINGS.quiet:
-    print(f'Devices added.: {len(devices_done)}, source {label}')
-
-    return topology_data
-
 
 def create_l3v4_topology(
         ignore_hosts: Sequence[str],
@@ -541,7 +504,7 @@ def create_l3v4_topology(
             emblem = EMBLEMS.ip_network
             try:
                 ipv4_info = Ipv4Info(**_entry)
-            except TypeError as e:
+            except TypeError:  # as e
                 LOGGER.warning(f'Drop IPv4 address data for host: {host}, data: {_entry}')
                 continue
 
@@ -550,11 +513,16 @@ def create_l3v4_topology(
                 continue
 
             if ipv4_info.cidr == 32:  # drop host addresses
-                LOGGER.info(f'host: {host} dropped host address: {ipv4_info.address}/{ipv4_info.cidr}')
+                LOGGER.info(
+                    f'host: {host} dropped host address: {ipv4_info.address}/{ipv4_info.cidr}'
+                )
                 continue
 
             if ipv4_info.type.lower() != 'ipv4':  # drop if not ipv4
-                LOGGER.warning(f'host: {host} dropped non ipv4 address: {ipv4_info.address}, type: {ipv4_info.type}')
+                LOGGER.warning(
+                    f'host: {host} dropped non ipv4 address: {ipv4_info.address},'
+                    ' type: {ipv4_info.type}'
+                )
                 continue
 
             if is_ignore_ipv4(ipv4_info.address, ignore_ips):
@@ -626,14 +594,11 @@ def create_l3v4_topology(
                     left=network, right=f'{ipv4_info.address}@{ipv4_info.device}@{host}',
                 )
 
-    LOGGER.info(msg=f'Devices added: {len(host_list)}, source L3v4')
-    # if not SETTINGS.quiet:
-    print(f'Devices added.: {len(host_list)}, source L3v4')
-
 
 if __name__ == '__main__':
     start_time = time_ns()
     SETTINGS = Settings(vars(parse_arguments()))
+
     sys.stdout = StdoutQuiet(quiet=SETTINGS.quiet)
 
     configure_logger(
@@ -643,7 +608,6 @@ if __name__ == '__main__':
     )
     LOGGER.info(msg='Data creation started')
 
-    # if not SETTINGS.quiet:
     print()
     print(
         f'Network Visualisation Data Creation Tool (NVDCT)\n'
@@ -653,25 +617,25 @@ if __name__ == '__main__':
     print()
     print(f'Start time....: {strftime(SETTINGS.time_format)}')
 
-    _backends = {
-        'LIVESTATUS': HostCacheLiveStatus,
-        'FILESYSTEM': HostCacheFileSystem,
-        'MULTISITE': HostCacheMultiSite,
-        'RESTAPI': HostCacheRestApi,
-    }
-    host_cache_backend = _backends.get(SETTINGS.backend, None)
-    if not host_cache_backend:
-        LOGGER.error(msg=f'Backend {SETTINGS.backend} not (yet) implemented')
-        sys.exit(ExitCodes.BACKEND_NOT_IMPLEMENTED.value)
-    elif SETTINGS.backend == 'RESTAPI':
-        HOST_CACHE = host_cache_backend(
-            pre_fetch=SETTINGS.pre_fetch,
-            api_port=SETTINGS.api_port
-        )
-    else:
-        HOST_CACHE = host_cache_backend(
-            pre_fetch=SETTINGS.pre_fetch,
-        )
+    match SETTINGS.backend:
+        case 'RESTAPI':
+            HOST_CACHE = HostCacheRestApi(
+                pre_fetch=SETTINGS.pre_fetch,
+                api_port=SETTINGS.api_port
+            )
+        case 'MULTISITE':
+            HOST_CACHE = HostCacheMultiSite(
+                pre_fetch=SETTINGS.pre_fetch,
+                filter_sites=SETTINGS.filter_sites,
+                sites = SETTINGS.sites,
+            )
+        case 'LIVESTATUS':
+            HOST_CACHE = HostCacheLiveStatus(
+                pre_fetch=SETTINGS.pre_fetch,
+            )
+        case _:
+            LOGGER.error(msg=f'Backend {SETTINGS.backend} not (yet) implemented')
+            sys.exit(ExitCodes.BACKEND_NOT_IMPLEMENTED.value)
 
     HOST_MAP = SETTINGS.host_map
     DROP_HOSTS = SETTINGS.drop_hosts
@@ -717,27 +681,26 @@ if __name__ == '__main__':
     for job in jobs:
         match job:
             case 'STATIC':
-                topology: Dict | None = create_static_connections(
+                label = 'static'
+                create_static_connections(
                     connections=SETTINGS.static_connections
                 )
-                label = 'static'
             case 'L3v4':
                 topology = None
                 label = 'l3v4'
-                if SETTINGS.new_format:
-                    create_l3v4_topology(
-                        ignore_hosts=SETTINGS.l3v4_ignore_hosts,
-                        ignore_ips=SETTINGS.l3v4_ignore_ips,
-                        ignore_wildcard=SETTINGS.l3v4_ignore_wildcard,
-                        summarize=SETTINGS.l3v4_summarize,
-                        replace=SETTINGS.l3v4_replace,
-                        skip_if=SETTINGS.skip_l3_if,
-                        skip_ip=SETTINGS.skip_l3_ip
-                    )
+                create_l3v4_topology(
+                    ignore_hosts=SETTINGS.l3v4_ignore_hosts,
+                    ignore_ips=SETTINGS.l3v4_ignore_ips,
+                    ignore_wildcard=SETTINGS.l3v4_ignore_wildcard,
+                    summarize=SETTINGS.l3v4_summarize,
+                    replace=SETTINGS.l3v4_replace,
+                    skip_if=SETTINGS.skip_l3_if,
+                    skip_ip=SETTINGS.skip_l3_ip
+                )
             case _:
                 label = job.label.lower()
                 columns = job.columns.split(',')
-                topology = create_l2_topology(
+                create_l2_topology(
                     seed_devices=SETTINGS.seed_devices,
                     path_in_inventory=job.path,
                     inv_columns=InventoryColumns(
@@ -748,52 +711,42 @@ if __name__ == '__main__':
                     label=label,
                 )
 
-        if SETTINGS.new_format:
-            LOGGER.info(f'Save topology {label} in new format')
-            NV_CONNECTIONS.add_meta_data_to_connections(
-                nv_objects=NV_OBJECTS,
-                speed_map=MAP_SPEED_TO_THICKNESS,
-            )
-            if not SETTINGS.loglevel == DEBUG:
-                connections = NV_CONNECTIONS.nv_connections
-            else:
-                connections = sorted(NV_CONNECTIONS.nv_connections)
-            _data = {
-                'version': 1,
-                'name': label,
-                'objects': NV_OBJECTS.nv_objects if not SETTINGS.loglevel == DEBUG else dict(
-                    sorted(NV_OBJECTS.nv_objects.items())
-                ),
-                'connections': connections
-            }
-            save_data_to_file(
-                data=_data,
-                path=(
-                    f'{SETTINGS.omd_root}/{SETTINGS.topology_save_path}/'
-                    f'{SETTINGS.output_directory}'
-                ),
-                file=f'data_{label}.json',
-                make_default=SETTINGS.default,
-            )
+        NV_CONNECTIONS.add_meta_data_to_connections(
+            nv_objects=NV_OBJECTS,
+            speed_map=MAP_SPEED_TO_THICKNESS,
+        )
+        if not SETTINGS.loglevel == DEBUG:
+            connections = NV_CONNECTIONS.nv_connections
+        else:
+            connections = sorted(NV_CONNECTIONS.nv_connections)
+        _data = {
+            'version': 1,
+            'name': label,
+            'objects': NV_OBJECTS.nv_objects if not SETTINGS.loglevel == DEBUG else dict(
+                sorted(NV_OBJECTS.nv_objects.items())
+            ),
+            'connections': connections
+        }
+        save_data_to_file(
+            data=_data,
+            path=(
+                f'{SETTINGS.omd_root}/{SETTINGS.topology_save_path}/'
+                f'{SETTINGS.output_directory}'
+            ),
+            file=f'data_{label}.json',
+            make_default=SETTINGS.default,
+        )
+
+        message = (
+            f'Source {label:.<7s}: Devices/Objects/Connections added {NV_OBJECTS.host_count}/'
+            f'{len(NV_OBJECTS.nv_objects)}/{len(NV_CONNECTIONS.nv_connections)}'
+        )
+        LOGGER.info(msg=message)
+        print(message)
 
         NV_OBJECTS = NvObjects()
         NV_CONNECTIONS = NvConnections()
 
-        if topology:
-            final_topology = merge_topologies(topo_pri=topology, topo_sec=final_topology)
-
-    if final_topology and not SETTINGS.new_format:
-        LOGGER.info('Save topology in CMK 2.2.x format')
-
-        save_topology(
-            data=final_topology,
-            base_directory=f'{SETTINGS.omd_root}/{SETTINGS.topology_save_path}',
-            output_directory=SETTINGS.output_directory,
-            topology_file_name=SETTINGS.topology_file_name,
-            dont_compare=SETTINGS.dont_compare,
-            make_default=SETTINGS.default,
-        )
-
     if SETTINGS.keep:
         remove_old_data(
             keep=SETTINGS.keep,
@@ -802,7 +755,6 @@ if __name__ == '__main__':
             protected=SETTINGS.protected_topologies,
         )
 
-    # if not SETTINGS.quiet:
     print(f'Time taken....: {(time_ns() - start_time) / 1e9}/s')
     print(f'End time......: {strftime(SETTINGS.time_format)}')
     print()
diff --git a/source/packages/nvdct b/source/packages/nvdct
index da6ca14..61fa095 100644
--- a/source/packages/nvdct
+++ b/source/packages/nvdct
@@ -8,9 +8,8 @@
                 '\n'
                 'Features:\n'
                 '\n'
-                ' - Ready for CMK 2.3.0\n'
                 ' - Create Layer 2 (CDP/LLDP) topology data\n'
-                ' - Create Layer 3 (IPv4) topology data (CMK2.3.0 only)\n'
+                ' - Create Layer 3 (IPv4) topology data\n'
                 ' - Highlight connection issues (Speed, Duplex/Half duplex, '
                 'Native VLAN)\n'
                 ' - Read connection data from the Checkmk HW/SW inventory.\n'
@@ -19,16 +18,13 @@
                 ' - Add custom connections (STATIC) for connections that are '
                 'not in the inventory\n'
                 ' - Optimized for my CDP, LLDP and IPv4 inventory plugins\n'
-                ' - Merge CDP, LLDP, STATIC topologies (CMK 2.2.0 only)\n'
                 ' - Can also be used with custom inventory plugins\n'
                 '\n'
                 'For more information about the network visualization plugin '
                 'see: \n'
                 'the announcement from schnetz  '
                 'https://forum.checkmk.com/t/network-visualization/41680\n'
-                'and the plugin on the Exchange (CMK 2.2.0 only, CMK 2.3.0 has '
-                'this built-in)  '
-                'https://exchange.checkmk.com/p/network-visualization\n'
+                '(CMK 2.3.0 has this  plugin built-in)  \n'
                 '\n'
                 'The inventory data could be created with my inventory '
                 'plugins:\n'
@@ -58,7 +54,7 @@
                    'htdocs/images/icons/location_80.png']},
  'name': 'nvdct',
  'title': 'Network Visualization Data Creation Tool (NVDCT)',
- 'version': '0.8.12-20240702',
- 'version.min_required': '2.2.0b1',
+ 'version': '0.9.0-20240923',
+ 'version.min_required': '2.3.0b1',
  'version.packaged': 'cmk-mkp-tool 0.2.0',
  'version.usable_until': '2.4.0p1'}
-- 
GitLab