def test_discovered_service_labels_repr(): labels = DiscoveredServiceLabels() labels.add_label(ServiceLabel(u"äbc", u"123")) labels.add_label(ServiceLabel(u"ccc", u"ddd")) assert repr( labels ) == "DiscoveredServiceLabels(ServiceLabel('ccc', 'ddd'), ServiceLabel('äbc', '123'))"
def test_ruleset_matcher_get_service_ruleset_values_labels(monkeypatch, hostname, service_description, expected_result): ts = Scenario() ts.add_host("host1") ts.set_autochecks("host1", [ Service("cpu.load", None, "CPU load", "{}", service_labels=DiscoveredServiceLabels( ServiceLabel(u"os", u"linux"), ServiceLabel(u"abc", u"xä"), ServiceLabel(u"hu", u"ha"), )) ]) ts.add_host("host2") ts.set_autochecks("host2", [ Service("cpu.load", None, "CPU load", "{}", service_labels=DiscoveredServiceLabels()), ]) config_cache = ts.apply(monkeypatch) matcher = config_cache.ruleset_matcher assert list( matcher.get_service_ruleset_values(config_cache.ruleset_match_object_of_service( hostname, service_description), ruleset=service_label_ruleset, is_binary=False)) == expected_result
def discovered_labels_of(self, hostname, service_desc): # type: (HostName, ServiceName) -> DiscoveredServiceLabels # Check if the autochecks for the given hostname were already read # The service in question might have no entry in the autochecks file # In this scenario it gets an empty DiscoveredServiceLabels entry host_results = self._discovered_labels_of.get(hostname) if host_results is not None: service_result = host_results.get(service_desc) if service_result is None: host_results[service_desc] = DiscoveredServiceLabels() return host_results[service_desc] # Only read the raw autochecks here. Do not compute the effective check parameters, # because that would invole ruleset matching which in would require the labels to # be already computed. # The following function reads the autochecks and populates the the discovered labels cache self._read_raw_autochecks_cached(hostname) result = self._discovered_labels_of.get(hostname, {}).get(service_desc) if result is None: # The service was not present in the autochecks, create an empty instance result = DiscoveredServiceLabels() self._discovered_labels_of.setdefault(hostname, {})[service_desc] = result return result
def _read_raw_autochecks_uncached( self, hostname: HostName, ) -> Sequence[_AutocheckService]: """Read automatically discovered checks of one host""" path = _autochecks_path_for(hostname) try: autochecks_raw = _load_raw_autochecks( path=path, check_variables=None, ) except SyntaxError as e: logger.exception("Syntax error in file %s: %s", path, e) if cmk.utils.debug.enabled(): raise return [] except Exception as e: logger.exception("Error in file %s:\n%s", path, e) if cmk.utils.debug.enabled(): raise return [] services = [] for entry in autochecks_raw: try: item = entry["item"] except TypeError: # pre 1.6 tuple! raise MKGeneralException( "Invalid check entry '%r' of host '%s' (%s) found. This " "entry is in pre Checkmk 1.6 format and needs to be converted. This is " 'normally done by "cmk-update-config -v" during "omd update". Please ' 'execute "cmk-update-config -v" for convertig the old configuration.' % (entry, hostname, path)) try: plugin_name = CheckPluginName( maincheckify(entry["check_plugin_name"])) assert item is None or isinstance(item, str) except Exception: raise MKGeneralException( "Invalid check entry '%r' of host '%s' (%s) found. This " "entry is in pre Checkmk 2.0 format and needs to be converted. This is " 'normally done by "cmk-update-config -v" during "omd update". Please ' 'execute "cmk-update-config -v" for convertig the old configuration.' % (entry, hostname, path)) labels = DiscoveredServiceLabels() for label_id, label_value in entry["service_labels"].items(): labels.add_label(ServiceLabel(label_id, label_value)) services.append( _AutocheckService( check_plugin_name=plugin_name, item=item, discovered_parameters=entry["parameters"], service_labels=labels, )) return services
def _parse_discovered_service_label_from_ast(ast_service_labels): # type: (ast.Dict) -> DiscoveredServiceLabels labels = DiscoveredServiceLabels() if not hasattr(ast_service_labels, "keys"): return labels for key, value in zip(ast_service_labels.keys, ast_service_labels.values): if key is not None: # mypy does not get the types of the ast objects here labels.add_label(ServiceLabel( key.s, value.s)) # type: ignore[attr-defined] return labels
def _parse_discovered_service_label_from_dict(dict_service_labels: Dict) -> DiscoveredServiceLabels: labels = DiscoveredServiceLabels() if not isinstance(dict_service_labels, dict): return labels for key, value in dict_service_labels.items(): if key is not None: labels.add_label(ServiceLabel( ensure_str(key), ensure_str(value), )) return labels
def test_discovered_service_labels_to_dict(): labels = DiscoveredServiceLabels() assert labels.to_dict() == {} labels["äbc"] = "123" labels["xyz"] = "blä" assert labels.to_dict() == { "äbc": "123", "xyz": "blä", }
def test_ruleset_matcher_get_service_ruleset_values_labels( monkeypatch: MonkeyPatch, hostname: HostName, service_description: str, expected_result: Sequence[str], ) -> None: ts = Scenario() ts.add_host(HostName("host1")) ts.set_autochecks( HostName("host1"), [ Service( CheckPluginName("cpu_load"), None, "CPU load", "{}", service_labels=DiscoveredServiceLabels( ServiceLabel("os", "linux"), ServiceLabel("abc", "xä"), ServiceLabel("hu", "ha"), ), ) ], ) ts.add_host(HostName("host2")) ts.set_autochecks( HostName("host2"), [ Service( CheckPluginName("cpu_load"), None, "CPU load", "{}", service_labels=DiscoveredServiceLabels(), ), ], ) config_cache = ts.apply(monkeypatch) matcher = config_cache.ruleset_matcher assert (list( matcher.get_service_ruleset_values( config_cache.ruleset_match_object_of_service( hostname, ServiceName(service_description)), ruleset=service_label_ruleset, is_binary=False, )) == expected_result)
def __init__(self, check_plugin_name, item, description, parameters, service_labels=None): # type: (CheckPluginName, Item, Text, CheckParameters, DiscoveredServiceLabels) -> None self._check_plugin_name = check_plugin_name self._item = item self._description = description self._parameters = parameters self._service_labels = service_labels or DiscoveredServiceLabels()
def __init__( self, item: Item, parameters: LegacyCheckParameters = None, service_labels: Optional[DiscoveredServiceLabels] = None) -> None: self.item = item self.parameters = parameters self.service_labels = service_labels or DiscoveredServiceLabels()
def __init__(self, item: Item, parameters: LegacyCheckParameters = None, service_labels: DiscoveredServiceLabels = None, host_labels: DiscoveredHostLabels = None) -> None: self.item = item self.parameters = parameters self.service_labels = service_labels or DiscoveredServiceLabels() self.host_labels = host_labels or DiscoveredHostLabels()
def __init__(self, item, parameters=None, service_labels=None, host_labels=None): # type: (Item, CheckParameters, DiscoveredServiceLabels, DiscoveredHostLabels) -> None self.item = item self.parameters = parameters self.service_labels = service_labels or DiscoveredServiceLabels() self.host_labels = host_labels or DiscoveredHostLabels()
def discovered_labels_of(self, hostname, service_desc, service_description, get_check_variables): # type: (HostName, ServiceName, GetServiceDescription, GetCheckVariables) -> DiscoveredServiceLabels if hostname not in self._discovered_labels_of: # Only read the raw autochecks here, do not compute the effective # check parameters. The latter would involve ruleset matching which # in turn would require already computed labels. self._read_raw_autochecks(hostname, service_description, get_check_variables) if service_desc not in self._discovered_labels_of[hostname]: self._discovered_labels_of[hostname][service_desc] = DiscoveredServiceLabels() return self._discovered_labels_of[hostname][service_desc]
def __init__( self, check_plugin_name: CheckPluginName, item: Item, description: str, parameters: LegacyCheckParameters, service_labels: Optional[DiscoveredServiceLabels] = None, ) -> None: self._check_plugin_name = check_plugin_name self._item = item self._description = description self._service_labels = service_labels or DiscoveredServiceLabels() self._parameters = parameters
def __init__( self, check_plugin_name: CheckPluginName, item: Item, description: str, parameters: LegacyCheckParameters, service_labels: Optional[DiscoveredServiceLabels] = None, ) -> None: self.check_plugin_name: Final = check_plugin_name self.item: Final = item self.description: Final = description self.service_labels: Final = service_labels or DiscoveredServiceLabels() self.parameters: Final = parameters
def test_discovered_service_init(): ser = discovery.Service(CheckPluginName("abc"), u"Item", u"ABC Item", None) assert ser.check_plugin_name == CheckPluginName("abc") assert ser.item == u"Item" assert ser.description == u"ABC Item" assert ser.parameters is None assert ser.service_labels.to_dict() == {} ser = discovery.Service(CheckPluginName("abc"), u"Item", u"ABC Item", None, DiscoveredServiceLabels(ServiceLabel(u"läbel", u"lübel"))) assert ser.service_labels.to_dict() == {u"läbel": u"lübel"} with pytest.raises(AttributeError): ser.xyz = "abc" # type: ignore[attr-defined] # pylint: disable=assigning-non-slot
def _enriched_discovered_services( host_name: HostName, check_plugin_name: CheckPluginName, plugins_services: checking_classes.DiscoveryResult, ) -> Generator[Service, None, None]: for service in plugins_services: description = config.service_description(host_name, check_plugin_name, service.item) # make sanity check if not description: console.error( f"{host_name}: {check_plugin_name} returned empty service description - ignoring it.\n" ) continue yield Service( check_plugin_name=check_plugin_name, item=service.item, description=description, parameters=unwrap_parameters(service.parameters), # Convert from APIs ServiceLabel to internal ServiceLabel service_labels=DiscoveredServiceLabels(*(ServiceLabel(*l) for l in service.labels)), )
def _read_raw_autochecks_uncached( self, hostname: HostName, service_description: GetServiceDescription, ) -> List[Service]: """Read automatically discovered checks of one host""" path = _autochecks_path_for(hostname) try: autochecks_raw = _load_raw_autochecks( path=path, check_variables=None, ) except SyntaxError as e: console.verbose("Syntax error in file %s: %s\n", path, e, stream=sys.stderr) if cmk.utils.debug.enabled(): raise return [] except Exception as e: console.verbose("Error in file %s:\n%s\n", path, e, stream=sys.stderr) if cmk.utils.debug.enabled(): raise return [] services: List[Service] = [] for entry in autochecks_raw: try: item = entry["item"] except TypeError: # pre 1.6 tuple! raise MKGeneralException( "Invalid check entry '%r' of host '%s' (%s) found. This " "entry is in pre Checkmk 1.6 format and needs to be converted. This is " "normally done by \"cmk-update-config -v\" during \"omd update\". Please " "execute \"cmk-update-config -v\" for convertig the old configuration." % (entry, hostname, path)) try: plugin_name = CheckPluginName( maincheckify(entry["check_plugin_name"])) assert item is None or isinstance(item, str) except Exception: raise MKGeneralException( "Invalid check entry '%r' of host '%s' (%s) found. This " "entry is in pre Checkmk 1.7 format and needs to be converted. This is " "normally done by \"cmk-update-config -v\" during \"omd update\". Please " "execute \"cmk-update-config -v\" for convertig the old configuration." % (entry, hostname, path)) labels = DiscoveredServiceLabels() for label_id, label_value in entry["service_labels"].items(): labels.add_label(ServiceLabel(label_id, label_value)) try: description = service_description(hostname, plugin_name, item) except Exception: continue # ignore services.append( Service( check_plugin_name=plugin_name, item=item, description=description, parameters=entry["parameters"], service_labels=labels, )) return services
def _read_raw_autochecks_uncached( self, hostname: HostName, service_description: GetServiceDescription, ) -> List[Service]: """Read automatically discovered checks of one host""" path = _autochecks_path_for(hostname) try: autochecks_raw = _load_raw_autochecks( path=path, check_variables=None, ) except SyntaxError as e: console.verbose("Syntax error in file %s: %s\n", path, e, stream=sys.stderr) if cmk.utils.debug.enabled(): raise return [] except Exception as e: console.verbose("Error in file %s:\n%s\n", path, e, stream=sys.stderr) if cmk.utils.debug.enabled(): raise return [] services: List[Service] = [] for entry in autochecks_raw: if isinstance(entry, tuple): raise MKGeneralException( "Invalid check entry '%r' of host '%s' (%s) found. This " "entry is in pre Checkmk 1.6 format and needs to be converted. This is " "normally done by \"cmk-update-config -v\" during \"omd update\". Please " "execute \"cmk-update-config -v\" for convertig the old configuration." % (entry, hostname, path)) labels = DiscoveredServiceLabels() for label_id, label_value in entry["service_labels"].items(): labels.add_label(ServiceLabel(label_id, label_value)) # With Check_MK 1.2.7i3 items are now defined to be unicode strings. Convert # items from existing autocheck files for compatibility. TODO remove this one day item = entry["item"] if not isinstance(entry["check_plugin_name"], str): raise MKGeneralException( "Invalid entry '%r' in check table of host '%s': " "The check type must be a string." % (entry, hostname)) check_plugin_name_str = str(entry["check_plugin_name"]) # TODO (mo): centralize maincheckify: CMK-4295 check_plugin_name = CheckPluginName( maincheckify(check_plugin_name_str)) try: description = service_description(hostname, check_plugin_name, item) except Exception: continue # ignore services.append( Service( check_plugin_name=check_plugin_name_str, item=item, description=description, parameters=entry["parameters"], service_labels=labels, )) return services
def test_remove_autochecks_file(): assert autochecks.has_autochecks("host") is False autochecks.save_autochecks_file("host", []) assert autochecks.has_autochecks("host") is True autochecks.remove_autochecks_file("host") assert autochecks.has_autochecks("host") is False @pytest.mark.parametrize("items,expected_content", [ ([], "[\n]\n"), ([ discovery.DiscoveredService( 'df', u'/xyz', u"Filesystem /xyz", "None", DiscoveredServiceLabels(ServiceLabel(u"x", u"y"))), discovery.DiscoveredService( 'df', u'/', u"Filesystem /", "{}", DiscoveredServiceLabels(ServiceLabel(u"x", u"y"))), discovery.DiscoveredService( 'cpu.loads', None, "CPU load", "cpuload_default_levels", DiscoveredServiceLabels(ServiceLabel(u"x", u"y"))), ], """[ {'check_plugin_name': 'cpu.loads', 'item': None, 'parameters': cpuload_default_levels, 'service_labels': {u'x': u'y'}}, {'check_plugin_name': 'df', 'item': u'/', 'parameters': {}, 'service_labels': {u'x': u'y'}}, {'check_plugin_name': 'df', 'item': u'/xyz', 'parameters': None, 'service_labels': {u'x': u'y'}}, ]\n"""), ]) def test_save_autochecks_file(items, expected_content): autochecks.save_autochecks_file("host", items)
autochecks.remove_autochecks_file(HostName("host")) assert autochecks.has_autochecks(HostName("host")) is False @pytest.mark.parametrize( "items,expected_content", [ ([], "[\n]\n"), ( [ discovery.Service( CheckPluginName("df"), "/xyz", "Filesystem /xyz", None, DiscoveredServiceLabels(ServiceLabel("x", "y")), ), discovery.Service( CheckPluginName("df"), "/", "Filesystem /", {}, DiscoveredServiceLabels(ServiceLabel("x", "y")), ), discovery.Service( CheckPluginName("cpu_loads"), None, "CPU load", {}, DiscoveredServiceLabels(ServiceLabel("x", "y")), ),
class AutochecksManager: """Read autochecks from the configuration Autochecks of a host are once read and cached for the whole lifetime of the AutochecksManager.""" def __init__(self) -> None: super().__init__() self._autochecks: Dict[HostName, List[Service]] = {} # Extract of the autochecks: This cache is populated either on the way while # processing get_autochecks_of() or when directly calling discovered_labels_of(). self._discovered_labels_of: Dict[HostName, Dict[ServiceName, DiscoveredServiceLabels]] = {} self._raw_autochecks_cache: Dict[HostName, Sequence[_AutocheckService]] = {} def get_autochecks_of( self, hostname: HostName, compute_check_parameters: ComputeCheckParameters, get_service_description: GetServiceDescription, get_effective_hostname: HostOfClusteredService, ) -> List[Service]: if hostname not in self._autochecks: self._autochecks[hostname] = list( self._get_autochecks_of_uncached( hostname, compute_check_parameters, get_service_description, get_effective_hostname, )) return self._autochecks[hostname] def _get_autochecks_of_uncached( self, hostname: HostName, compute_check_parameters: ComputeCheckParameters, get_service_description: GetServiceDescription, get_effective_hostname: HostOfClusteredService, ) -> Iterable[Service]: """Read automatically discovered checks of one host""" for autocheck_service in self._read_raw_autochecks(hostname): try: service_name = get_service_description( hostname, autocheck_service.check_plugin_name, autocheck_service.item) except Exception: # I dont't really know why this is ignored. Feels utterly wrong. continue yield Service( check_plugin_name=autocheck_service.check_plugin_name, item=autocheck_service.item, description=service_name, parameters=compute_check_parameters( get_effective_hostname(hostname, service_name), autocheck_service.check_plugin_name, autocheck_service.item, autocheck_service.discovered_parameters, ), service_labels=autocheck_service.service_labels, ) def discovered_labels_of( self, hostname: HostName, service_desc: ServiceName, get_service_description: GetServiceDescription, ) -> DiscoveredServiceLabels: # NOTE: this returns an empty labels object for non-existing services with suppress(KeyError): return self._discovered_labels_of[hostname][service_desc] hosts_labels = self._discovered_labels_of.setdefault(hostname, {}) # Only read the raw autochecks here, do not compute the effective # check parameters. The latter would involve ruleset matching which # in turn would require already computed labels. for autocheck_service in self._read_raw_autochecks(hostname): try: hosts_labels[get_service_description( hostname, autocheck_service.check_plugin_name, autocheck_service.item)] = autocheck_service.service_labels except Exception: continue # ignore if (labels := hosts_labels.get(service_desc)) is not None: return labels return DiscoveredServiceLabels()
def labels(request): if request.param == "host": return DiscoveredHostLabels() return DiscoveredServiceLabels()
def _read_raw_autochecks_of(self, hostname): # type: (HostName) -> List[Service] """Read automatically discovered checks of one host""" basedir = cmk.utils.paths.autochecks_dir filepath = basedir + '/' + hostname + '.mk' result = [] # type: List[Service] if not os.path.exists(filepath): return result check_config = config.get_check_variables() try: cmk.base.console.vverbose("Loading autochecks from %s\n", filepath) autochecks_raw = eval( open(filepath).read().decode("utf-8"), check_config, check_config) # type: List[Dict] except SyntaxError as e: cmk.base.console.verbose("Syntax error in file %s: %s\n", filepath, e, stream=sys.stderr) if cmk.utils.debug.enabled(): raise return result except Exception as e: cmk.base.console.verbose("Error in file %s:\n%s\n", filepath, e, stream=sys.stderr) if cmk.utils.debug.enabled(): raise return result for entry in autochecks_raw: if isinstance(entry, tuple): raise MKGeneralException( "Invalid check entry '%r' of host '%s' (%s) found. This " "entry is in pre Checkmk 1.6 format and needs to be converted. This is " "normally done by \"cmk-update-config -v\" during \"omd update\". Please " "execute \"cmk-update-config -v\" for convertig the old configuration." % (entry, hostname, filepath)) labels = DiscoveredServiceLabels() for label_id, label_value in entry["service_labels"].items(): labels.add_label(ServiceLabel(label_id, label_value)) # With Check_MK 1.2.7i3 items are now defined to be unicode strings. Convert # items from existing autocheck files for compatibility. TODO remove this one day item = entry["item"] if isinstance(item, str): item = convert_to_unicode(item) if not isinstance(entry["check_plugin_name"], six.string_types): raise MKGeneralException("Invalid entry '%r' in check table of host '%s': " "The check type must be a string." % (entry, hostname)) check_plugin_name = str(entry["check_plugin_name"]) try: description = config.service_description(hostname, check_plugin_name, item) except Exception: continue # ignore result.append( Service( check_plugin_name=check_plugin_name, item=item, description=description, parameters=entry["parameters"], service_labels=labels, )) return result