From bfa2c79f8f8fa26c4846750c493f11c001fa5123 Mon Sep 17 00:00:00 2001 From: Mathias Laurin Date: Tue, 17 Oct 2023 10:58:29 +0200 Subject: [PATCH] Move hosts container to hostaddress * make it a frozen dataclass * rename to `Hosts`---it's a container of hosts, independently of how it gets its filled CMK-14467 Change-Id: I644e98db2ca8e212bbbbeae584998eae37aaafde --- cmk/base/config.py | 43 +++++------------------- cmk/base/core_nagios.py | 14 +++----- cmk/utils/hostaddress.py | 24 ++++++++++++- tests/unit/cmk/base/test_config.py | 15 +-------- tests/unit/cmk/utils/test_hostaddress.py | 19 +++++++++++ 5 files changed, 56 insertions(+), 59 deletions(-) create mode 100644 tests/unit/cmk/utils/test_hostaddress.py diff --git a/cmk/base/config.py b/cmk/base/config.py index 27bf8a75ada..6480f2757f1 100644 --- a/cmk/base/config.py +++ b/cmk/base/config.py @@ -21,7 +21,6 @@ import socket import struct import sys -from collections import Counter from collections.abc import ( Callable, Container, @@ -62,7 +61,7 @@ ) from cmk.utils.config_path import ConfigPath from cmk.utils.exceptions import MKGeneralException, MKIPAddressLookupError, MKTerminate, OnError -from cmk.utils.hostaddress import HostAddress, HostName +from cmk.utils.hostaddress import HostAddress, HostName, Hosts from cmk.utils.http_proxy_config import http_proxy_config_from_user_setting, HTTPProxyConfig from cmk.utils.labels import Labels from cmk.utils.log import console @@ -1883,42 +1882,18 @@ def lookup_ip_address( # +----------------------------------------------------------------------+ -class HostsConfig: - def __init__( - self, - *, - hosts: Sequence[HostName], - clusters: Sequence[HostName], # pylint: disable=redefined-outer-name - shadow_hosts: Sequence[HostName], # pylint: disable=redefined-outer-name - ) -> None: - self.hosts: Final = hosts - self.clusters: Final = clusters - self.shadow_hosts: Final = shadow_hosts - - def duplicates(self, /, pred: Callable[[HostName], bool]) -> Iterable[HostName]: - return ( - hn - for hn, count in Counter( - hn - for hn in itertools.chain(self.hosts, self.clusters, self.shadow_hosts) - if pred(hn) - ).items() - if count > 1 - ) - - @classmethod - def from_config(cls) -> HostsConfig: - return cls( - hosts=strip_tags(all_hosts), - clusters=strip_tags(clusters), - shadow_hosts=list(_get_shadow_hosts()), - ) +def make_hosts_config() -> Hosts: + return Hosts( + hosts=strip_tags(all_hosts), + clusters=strip_tags(clusters), + shadow_hosts=list(_get_shadow_hosts()), + ) class ConfigCache: def __init__(self) -> None: super().__init__() - self.hosts_config = HostsConfig(hosts=(), clusters=(), shadow_hosts=()) + self.hosts_config = Hosts(hosts=(), clusters=(), shadow_hosts=()) self.__enforced_services_table: dict[ HostName, Mapping[ @@ -1948,7 +1923,7 @@ def __init__(self) -> None: def initialize(self) -> ConfigCache: self._initialize_caches() - self.hosts_config = HostsConfig.from_config() + self.hosts_config = make_hosts_config() self._setup_clusters_nodes_cache() tag_to_group_map = ConfigCache.get_tag_to_group_map() diff --git a/cmk/base/core_nagios.py b/cmk/base/core_nagios.py index e0f6f0f1dc0..d92fa8c5056 100644 --- a/cmk/base/core_nagios.py +++ b/cmk/base/core_nagios.py @@ -25,7 +25,7 @@ from cmk.utils.check_utils import section_name_of from cmk.utils.config_path import VersionedConfigPath from cmk.utils.exceptions import MKGeneralException -from cmk.utils.hostaddress import HostAddress, HostName +from cmk.utils.hostaddress import HostAddress, HostName, Hosts from cmk.utils.labels import Labels from cmk.utils.licensing.handler import LicensingHandler from cmk.utils.log import console @@ -44,13 +44,7 @@ import cmk.base.ip_lookup as ip_lookup import cmk.base.obsolete_output as out import cmk.base.utils -from cmk.base.config import ( - ConfigCache, - HostgroupName, - HostsConfig, - ObjectAttributes, - ServicegroupName, -) +from cmk.base.config import ConfigCache, HostgroupName, ObjectAttributes, ServicegroupName from cmk.base.core_config import ( AbstractServiceID, CollectedHostLabels, @@ -146,10 +140,10 @@ def write(self, x: str) -> None: def _validate_licensing( - hosts_config: HostsConfig, licensing_handler: LicensingHandler, licensing_counter: Counter + hosts: Hosts, licensing_handler: LicensingHandler, licensing_counter: Counter ) -> None: if block_effect := licensing_handler.effect_core( - licensing_counter["services"], len(hosts_config.shadow_hosts) + licensing_counter["services"], len(hosts.shadow_hosts) ).block: raise MKGeneralException(block_effect.message_raw) diff --git a/cmk/utils/hostaddress.py b/cmk/utils/hostaddress.py index 6f91caa3039..13e36a5a887 100644 --- a/cmk/utils/hostaddress.py +++ b/cmk/utils/hostaddress.py @@ -3,11 +3,33 @@ # This file is part of Checkmk (https://checkmk.com). It is subject to the terms and # conditions defined in the file COPYING, which is part of this source code package. +import itertools +from collections import Counter +from collections.abc import Callable, Iterable, Sequence +from dataclasses import dataclass from typing import NewType, TypeAlias -__all__ = ["HostAddress", "HostName"] +__all__ = ["HostAddress", "Hosts", "HostName"] HostAddress = NewType("HostAddress", str) # Let us be honest here, we do not actually make a difference # between HostAddress and HostName in our code. HostName: TypeAlias = HostAddress + + +@dataclass(frozen=True) +class Hosts: + hosts: Sequence[HostName] + clusters: Sequence[HostName] + shadow_hosts: Sequence[HostName] + + def duplicates(self, /, pred: Callable[[HostName], bool]) -> Iterable[HostName]: + return ( + hn + for hn, count in Counter( + hn + for hn in itertools.chain(self.hosts, self.clusters, self.shadow_hosts) + if pred(hn) + ).items() + if count > 1 + ) diff --git a/tests/unit/cmk/base/test_config.py b/tests/unit/cmk/base/test_config.py index 09ab2d6b3a6..165addd45a8 100644 --- a/tests/unit/cmk/base/test_config.py +++ b/tests/unit/cmk/base/test_config.py @@ -42,23 +42,10 @@ from cmk.base.api.agent_based.checking_classes import CheckPlugin as CheckPluginAPI from cmk.base.api.agent_based.register.utils_legacy import LegacyCheckDefinition from cmk.base.api.agent_based.type_defs import SNMPSectionPlugin -from cmk.base.config import ConfigCache, HostsConfig, ip_address_of +from cmk.base.config import ConfigCache, ip_address_of from cmk.base.ip_lookup import AddressFamily -def test_duplicate_hosts() -> None: - hostnames = ( - HostName("un"), - HostName("deux"), - HostName("deux"), - HostName("trois"), - HostName("trois"), - HostName("trois"), - ) - hosts_config = HostsConfig(hosts=hostnames, clusters=(), shadow_hosts=()) - assert list(hosts_config.duplicates(lambda *args, **kw: True)) == ["deux", "trois"] - - def test_all_offline_hosts(monkeypatch: MonkeyPatch) -> None: ts = Scenario() ts.add_host(HostName("blub"), tags={TagGroupID("criticality"): TagID("offline")}) diff --git a/tests/unit/cmk/utils/test_hostaddress.py b/tests/unit/cmk/utils/test_hostaddress.py new file mode 100644 index 00000000000..fef2ca10f68 --- /dev/null +++ b/tests/unit/cmk/utils/test_hostaddress.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# Copyright (C) 2019 Checkmk GmbH - License: GNU General Public License v2 +# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and +# conditions defined in the file COPYING, which is part of this source code package. + +from cmk.utils.hostaddress import HostName, Hosts + + +def test_duplicate_hosts() -> None: + hostnames = ( + HostName("un"), + HostName("deux"), + HostName("deux"), + HostName("trois"), + HostName("trois"), + HostName("trois"), + ) + hosts_config = Hosts(hosts=hostnames, clusters=(), shadow_hosts=()) + assert list(hosts_config.duplicates(lambda *args, **kw: True)) == ["deux", "trois"]