def _extract_snmp_sections( inf_info: Dict[InventoryPluginNameStr, InventoryInfo], plugin_file_lookup: Dict[str, str], ) -> None: for plugin_name, plugin_info in sorted(inv_info.items()): if 'snmp_info' not in plugin_info: continue section_name = section_name_of(plugin_name) if isinstance(agent_based_register.get_section_plugin(SectionName(section_name)), SNMPSectionPlugin): continue fallback_files = ([_include_file_path(i) for i in plugin_info.get('includes', [])] + [plugin_file_lookup[plugin_name]]) try: agent_based_register.add_section_plugin( create_snmp_section_plugin_from_legacy( section_name, {}, plugin_info['snmp_scan_function'], plugin_info['snmp_info'], scan_function_fallback_files=fallback_files, )) except (NotImplementedError, KeyError, AssertionError, ValueError): msg = config.AUTO_MIGRATION_ERR_MSG % ('section', plugin_name) if cmk.utils.debug.enabled(): raise MKGeneralException(msg) console.warning(msg)
def _extract_snmp_sections( inf_info: Dict[InventoryPluginNameStr, InventoryInfo], plugin_file_lookup: Dict[str, str], ) -> List[str]: errors = [] for plugin_name, plugin_info in sorted(inv_info.items()): if 'snmp_info' not in plugin_info: continue section_name = section_name_of(plugin_name) if isinstance(agent_based_register.get_section_plugin(SectionName(section_name)), SNMPSectionPlugin): continue fallback_files = ([_include_file_path(i) for i in plugin_info.get('includes', [])] + [plugin_file_lookup[plugin_name]]) try: agent_based_register.add_section_plugin( create_snmp_section_plugin_from_legacy( section_name, {}, plugin_info['snmp_scan_function'], plugin_info['snmp_info'], scan_function_fallback_files=fallback_files, # We have to validate, because we read inventory plugin files # directly, and do not know whether they changed. validate_creation_kwargs=True, )) except (NotImplementedError, KeyError, AssertionError, ValueError): msg = config.AUTO_MIGRATION_ERR_MSG % ('section', plugin_name) if cmk.utils.debug.enabled(): raise MKGeneralException(msg) errors.append(msg) return errors
def data(self): # type: () -> RawSNMPData info = {} # type: RawSNMPData for check_plugin_name, oid_info in self._oid_infos.items(): section_name = section_name_of(check_plugin_name) # Prevent duplicate data fetching of identical section in case of SNMP sub checks if section_name in info: self._logger.debug( "%s: Skip fetching data (section already fetched)", check_plugin_name) continue self._logger.debug("%s: Fetching data", check_plugin_name) # oid_info can now be a list: Each element of that list is interpreted as one real oid_info # and fetches a separate snmp table. get_snmp = snmp_table.get_snmp_table_cached if self._use_snmpwalk_cache else snmp_table.get_snmp_table if isinstance(oid_info, list): # branch: List[ABCSNMPTree] check_info = [] # type: List[SNMPTable] for entry in oid_info: check_info_part = get_snmp(self._snmp_config, check_plugin_name, entry) check_info.append(check_info_part) info[section_name] = check_info else: # branch: OIDInfo info[section_name] = get_snmp(self._snmp_config, check_plugin_name, oid_info) return info
def _extract_snmp_sections(): # type: () -> None for plugin_name, plugin_info in sorted(inv_info.items()): if 'snmp_info' not in plugin_info: continue section_name = section_name_of(plugin_name) if config.get_registered_section_plugin(PluginName(section_name)): continue fallback_files = ( [_include_file_path(i) for i in plugin_info.get('includes', [])] + [_plugin_file_lookup[plugin_name]]) try: snmp_section_plugin = create_snmp_section_plugin_from_legacy( section_name, {}, plugin_info['snmp_scan_function'], plugin_info['snmp_info'], scan_function_fallback_files=fallback_files, ) except (NotImplementedError, KeyError, AssertionError, ValueError): msg = config.AUTO_MIGRATION_ERR_MSG % ('section', plugin_name) if cmk.utils.debug.enabled(): raise MKGeneralException(msg) # TODO (mo): bring this back: #console.warning(msg) else: config.registered_snmp_sections[ snmp_section_plugin.name] = snmp_section_plugin
def _make_oid_infos(self): # type: () -> Dict[CheckPluginName, Union[OIDInfo, List[ABCSNMPTree]]] oid_infos = { } # Dict[CheckPluginName, Union[OIDInfo, List[ABCSNMPTree]]] raw_sections_to_process = self._get_raw_section_names_to_process() for check_plugin_name in self._sort_check_plugin_names( raw_sections_to_process): # Is this an SNMP table check? Then snmp_info specifies the OID to fetch # Please note, that if the check_plugin_name is foo.bar then we lookup the # snmp info for "foo", not for "foo.bar". section_name = section_name_of(check_plugin_name) oid_info, has_snmp_info = self._oid_info_from_section_name( section_name) if not has_snmp_info and check_plugin_name in self._fetched_raw_section_names: continue if oid_info is None: continue # This checks data is configured to be persisted (snmp_check_interval) and recent enough. # Skip gathering new data here. The persisted data will be added later if self._persisted_sections and section_name in self._persisted_sections: self._logger.debug( "%s: Skip fetching data (persisted info exists)", check_plugin_name) continue oid_infos[check_plugin_name] = oid_info return oid_infos
def test_create_section_plugin_from_legacy(config_check_info, snmp_info, migrated_agent_sections, migrated_snmp_sections): for name, check_info_dict in config_check_info.items(): # only test main checks if name != section_name_of(name): continue section_name = SectionName(name) with known_exceptions('section', name): section = migrated_agent_sections.get(section_name) if section is not None: assert isinstance(section, AgentSectionPlugin) else: section = migrated_snmp_sections.get(section_name) if section is None: raise NotImplementedError(name) assert isinstance(section, SNMPSectionPlugin) if section is None: continue original_parse_function = check_info_dict["parse_function"] if original_parse_function is not None: assert original_parse_function.__name__ == section.parse_function.__name__
def get_section_content( self, host_key: HostKey, management_board_info: str, check_plugin_name: CheckPluginNameStr, for_discovery: bool, service_description: Optional[ServiceName] = None) -> FinalSectionContent: """Prepares the section_content construct for a Check_MK check on ANY host The section_content construct is then handed over to the check, inventory or discovery functions for doing their work. If the host is a cluster, the sections from all its nodes is merged together here. Optionally the node info is added to the nodes section content. It handles the whole data and cares about these aspects: a) Extract the section_content for the given check_plugin_name b) Adds node_info to the section_content (if check asks for this) c) Applies the parse function (if check has some) d) Adds extra_sections (if check asks for this) and also applies node_info and extra_section handling to this It can return an section_content construct or None when there is no section content for this check available. """ section_name = section_name_of(check_plugin_name) nodes_of_clustered_service = self._get_nodes_of_clustered_service( host_key.hostname, service_description) cache_key = (host_key, management_board_info, section_name, for_discovery, bool(nodes_of_clustered_service)) try: return self._section_content_cache[cache_key] except KeyError: pass section_content = self._get_section_content( host_key._replace(source_type=SourceType.MANAGEMENT if management_board_info == LEGACY_MGMT_ONLY else SourceType.HOST), check_plugin_name, SectionName(section_name), for_discovery, nodes_of_clustered_service, ) # If we found nothing, see if we must check the management board: if (section_content is None and host_key.source_type is SourceType.HOST and management_board_info == LEGACY_HOST_PRECEDENCE): section_content = self._get_section_content( host_key._replace(source_type=SourceType.MANAGEMENT), check_plugin_name, SectionName(section_name), for_discovery, nodes_of_clustered_service, ) self._section_content_cache[cache_key] = section_content return section_content
def is_snmp_check(check_plugin_name: str) -> bool: cache = _runtime_cache.get_dict("is_snmp_check") try: return cache[check_plugin_name] except KeyError: snmp_checks = _runtime_cache.get_set("check_type_snmp") result = section_name_of(check_plugin_name) in snmp_checks cache[check_plugin_name] = result return result
def is_tcp_check(check_plugin_name): # type: (str) -> bool cache = _runtime_cache.get_dict("is_tcp_check") try: return cache[check_plugin_name] except KeyError: tcp_checks = _runtime_cache.get_set("check_type_tcp") result = section_name_of(check_plugin_name) in tcp_checks cache[check_plugin_name] = result return result
def test_create_section_plugin_from_legacy(inv_info): for name, inv_info_dict in inv_info.items(): if 'snmp_info' not in inv_info_dict: continue section_name = PluginName(section_name_of(name)) with known_exceptions(name): if section_name not in config.registered_snmp_sections: raise NotImplementedError(name) section = config.registered_snmp_sections[section_name] assert isinstance(section, SNMPSectionPlugin)
def _get_detection_spec_from_plugin_name(check_plugin_name, inv_info): # type: (CheckPluginName, Dict[str, Any]) -> Union[SNMPDetectSpec, Optional[ScanFunction]] # This function will hopefully shrink and finally disappear during API development. section_name = section_name_of(check_plugin_name) section_plugin = config.registered_snmp_sections.get(PluginName(section_name)) if section_plugin: return section_plugin.detect_spec # TODO (mo): migrate section definitions from inventory plugins to # section plugins and remove this conditional entirely info = inv_info[section_name] return info.get("snmp_scan_function")
def get_section_content( self, hostname, # type: HostName ipaddress, # type: Optional[HostAddress] check_plugin_name, # type: CheckPluginName for_discovery, # type: bool service_description=None # type: Optional[ServiceName] ): # type: (...) -> FinalSectionContent """Prepares the section_content construct for a Check_MK check on ANY host The section_content construct is then handed over to the check, inventory or discovery functions for doing their work. If the host is a cluster, the sections from all its nodes is merged together here. Optionally the node info is added to the nodes section content. It handles the whole data and cares about these aspects: a) Extract the section_content for the given check_plugin_name b) Adds node_info to the section_content (if check asks for this) c) Applies the parse function (if check has some) d) Adds extra_sections (if check asks for this) and also applies node_info and extra_section handling to this It can return an section_content construct or None when there is no section content for this check available. """ section_name = section_name_of(check_plugin_name) nodes_of_clustered_service = self._get_nodes_of_clustered_service( hostname, service_description) cache_key = (hostname, ipaddress, section_name, for_discovery, bool(nodes_of_clustered_service)) try: return self._section_content_cache[cache_key] except KeyError: section_content = self._get_section_content( hostname, ipaddress, check_plugin_name, section_name, for_discovery, nodes_of_clustered_service) self._section_content_cache[cache_key] = section_content return section_content
def test_no_subcheck_with_snmp_keywords(snmp_info): for name in snmp_info: assert name == section_name_of(name)
def _execute_check_legacy_mode(multi_host_sections, hostname, ipaddress, service): # type: (data_sources.MultiHostSections, HostName, Optional[HostAddress], Service) -> bool check_function = config.check_info[service.check_plugin_name].get( "check_function") if check_function is None: _submit_check_result(hostname, service.description, CHECK_NOT_IMPLEMENTED, None) return True # Make a bit of context information globally available, so that functions # called by checks know this context check_api_utils.set_service(service.check_plugin_name, service.description) item_state.set_item_state_prefix(service.check_plugin_name, service.item) section_name = section_name_of(service.check_plugin_name) section_content = None try: # TODO: There is duplicate code with discovery._execute_discovery(). Find a common place! try: section_content = multi_host_sections.get_section_content( hostname, ipaddress, config.get_management_board_precedence(section_name, config.check_info), section_name, for_discovery=False, service_description=service.description) except MKParseFunctionError as e: x = e.exc_info() # re-raise the original exception to not destory the trace. This may raise a MKCounterWrapped # exception which need to lead to a skipped check instead of a crash # TODO CMK-3729, PEP-3109 new_exception = x[0](x[1]) new_exception.__traceback__ = x[2] # type: ignore[attr-defined] raise new_exception # TODO: Move this to a helper function if section_content is None: # No data for this check type return False # Call the actual check function item_state.reset_wrapped_counters() raw_result = check_function( service.item, legacy_determine_check_params(service.parameters), section_content) result = sanitize_check_result(raw_result) item_state.raise_counter_wrap() except item_state.MKCounterWrapped as e: # handle check implementations that do not yet support the # handling of wrapped counters via exception on their own. # Do not submit any check result in that case: console.verbose("%-20s PEND - Cannot compute check result: %s\n", ensure_str(service.description), e) # Don't submit to core - we're done. return True except MKTimeout: raise except Exception: if cmk.utils.debug.enabled(): raise result = 3, cmk.base.crash_reporting.create_check_crash_dump( hostname, service.check_plugin_name, service.item, is_manual_check(hostname, service.check_plugin_name, service.item), service.parameters, service.description, section_content), [] _submit_check_result( hostname, service.description, result, _legacy_determine_cache_info(multi_host_sections, section_name), ) return True
def _do_all_checks_on_host(sources, host_config, ipaddress, only_check_plugin_names=None): # type: (data_sources.DataSources, config.HostConfig, Optional[HostAddress], Optional[List[str]]) -> Tuple[int, List[SectionName]] hostname = host_config.hostname # type: HostName config_cache = config.get_config_cache() num_success, missing_sections = 0, set() check_api_utils.set_hostname(hostname) belongs_to_cluster = len(config_cache.clusters_of(hostname)) > 0 services = check_table.get_precompiled_check_table( hostname, remove_duplicates=True, filter_mode="include_clustered" if belongs_to_cluster else None, ) # When check types are specified via command line, enforce them. Otherwise use the # list of checks defined by the check table. if only_check_plugin_names is None: only_check_plugins = { service.check_plugin_name for service in services } else: only_check_plugins = set(only_check_plugin_names) sources.enforce_check_plugin_names(only_check_plugins) # Gather the data from the sources multi_host_sections = sources.get_host_sections() def _is_not_of_host(host_name, service): return hostname != config_cache.host_of_clustered_service( hostname, service.description) # Filter out check types which are not used on the node if belongs_to_cluster: removed_plugins = { plugin for plugin in only_check_plugins if all( _is_not_of_host(hostname, service) for service in services if service.check_plugin_name == plugin) } only_check_plugins -= removed_plugins for service in services: if service.check_plugin_name not in only_check_plugins: continue if belongs_to_cluster and _is_not_of_host(hostname, service): continue if service_outside_check_period(config_cache, hostname, service.description): continue success = execute_check(multi_host_sections, host_config, ipaddress, service) if success: num_success += 1 else: missing_sections.add(section_name_of(service.check_plugin_name)) import cmk.base.inventory as inventory # pylint: disable=import-outside-toplevel inventory.do_inventory_actions_during_checking_for(sources, multi_host_sections, host_config, ipaddress) missing_section_list = sorted(missing_sections) return num_success, missing_section_list
def get_section_content( self, host_key: HostKey, management_board_info: str, check_plugin_name: str, for_discovery: bool, *, cluster_node_keys: Optional[List[HostKey]] = None, check_legacy_info: Dict[str, Dict[str, Any]], ) -> Union[None, ParsedSectionContent, List[ParsedSectionContent]]: """Prepares the section_content construct for a Check_MK check on ANY host The section_content construct is then handed over to the check, inventory or discovery functions for doing their work. If the host is a cluster, the sections from all its nodes is merged together here. Optionally the node info is added to the nodes section content. It handles the whole data and cares about these aspects: a) Extract the section_content for the given check_plugin_name b) Adds node_info to the section_content (if check asks for this) c) Applies the parse function (if check has some) It can return an section_content construct or None when there is no section content for this check available. """ section_name = section_name_of(check_plugin_name) cache_key = (host_key, management_board_info, section_name, for_discovery, bool(cluster_node_keys)) try: return self._section_content_cache[cache_key] except KeyError: pass section_content = self._get_section_content( host_key._replace(source_type=SourceType.MANAGEMENT if management_board_info == LEGACY_MGMT_ONLY else SourceType.HOST), check_plugin_name, SectionName(section_name), for_discovery, cluster_node_keys=cluster_node_keys, check_legacy_info=check_legacy_info, ) # If we found nothing, see if we must check the management board: if (section_content is None and host_key.source_type is SourceType.HOST and management_board_info == LEGACY_HOST_PRECEDENCE): section_content = self._get_section_content( host_key._replace(source_type=SourceType.MANAGEMENT), check_plugin_name, SectionName(section_name), for_discovery, cluster_node_keys=cluster_node_keys, check_legacy_info=check_legacy_info, ) self._section_content_cache[cache_key] = section_content return section_content
def is_snmp_plugin(check_plugin_name): # type: (str) -> bool section_name = section_name_of(check_plugin_name) return PluginName(section_name) in config.registered_snmp_sections
def is_snmp_plugin(check_plugin_name: str) -> bool: section_name = section_name_of(check_plugin_name) return SectionName(section_name) in config.registered_snmp_sections
def _execute_check_legacy_mode(multi_host_sections: MultiHostSections, hostname: HostName, ipaddress: Optional[HostAddress], service: Service) -> bool: check_function = config.check_info[service.check_plugin_name].get("check_function") if check_function is None: _submit_check_result(hostname, service.description, CHECK_NOT_IMPLEMENTED, None) return True # Make a bit of context information globally available, so that functions # called by checks know this context check_api_utils.set_service(service.check_plugin_name, service.description) item_state.set_item_state_prefix(service.check_plugin_name, service.item) section_name = section_name_of(service.check_plugin_name) section_content = None mgmt_board_info = config.get_management_board_precedence(section_name, config.check_info) try: # TODO: There is duplicate code with discovery._execute_discovery(). section_content = multi_host_sections.get_section_content( HostKey( hostname, ipaddress, SourceType.MANAGEMENT if mgmt_board_info == LEGACY_MGMT_ONLY else SourceType.HOST, ), mgmt_board_info, section_name, for_discovery=False, service_description=service.description, ) # TODO: Move this to a helper function if section_content is None: # No data for this check type return False # Call the actual check function item_state.reset_wrapped_counters() used_params = legacy_determine_check_params(service.parameters) raw_result = check_function(service.item, used_params, section_content) result = sanitize_check_result(raw_result) item_state.raise_counter_wrap() except item_state.MKCounterWrapped as e: # handle check implementations that do not yet support the # handling of wrapped counters via exception on their own. # Do not submit any check result in that case: console.verbose("%-20s PEND - Cannot compute check result: %s\n", ensure_str(service.description), e) # Don't submit to core - we're done. return True except MKTimeout: raise except Exception: if cmk.utils.debug.enabled(): raise result = 3, cmk.base.crash_reporting.create_check_crash_dump( hostname, service.check_plugin_name, { "item": service.item, "params": used_params, "section_content": section_content }, is_manual_check(hostname, service.check_plugin_name, service.item), service.description, ), [] _submit_check_result( hostname, service.description, result, _legacy_determine_cache_info(multi_host_sections, SectionName(section_name)), ) return True
def is_snmp_plugin(check_plugin_name): # type: (str) -> bool section_name = section_name_of(check_plugin_name) return "snmp_info" in inv_info.get(section_name, {}) \ or cmk.base.check_utils.is_snmp_check(check_plugin_name)