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 _snmp_scan_find_sections( sections: Iterable[SNMPScanSection], *, do_snmp_scan: bool, on_error: str, backend: ABCSNMPBackend, ) -> Set[SectionName]: found_sections: Set[SectionName] = set() for name, specs in sections: try: if _evaluate_snmp_detection( specs, name, do_snmp_scan, backend=backend, ): found_sections.add(name) except MKGeneralException: # some error messages which we explicitly want to show to the user # should be raised through this raise except Exception: if on_error == "warn": console.warning(" Exception in SNMP scan function of %s" % name) elif on_error == "raise": raise return found_sections
def _find_sections( sections: Iterable[SNMPScanSection], *, on_error: str, backend: ABCSNMPBackend, ) -> Set[SectionName]: found_sections: Set[SectionName] = set() for name, specs in sections: oid_value_getter = functools.partial( snmp_modes.get_single_oid, section_name=name, backend=backend, ) try: if evaluate_snmp_detection( detect_spec=specs, oid_value_getter=oid_value_getter, ): found_sections.add(name) except MKGeneralException: # some error messages which we explicitly want to show to the user # should be raised through this raise except Exception: if on_error == "warn": console.warning(" Exception in SNMP scan function of %s" % name) elif on_error == "raise": raise return found_sections
def _commandline_discovery_on_host( host_name: HostName, ipaddress: Optional[HostAddress], parsed_sections_broker: ParsedSectionsBroker, run_plugin_names: Container[CheckPluginName], only_new: bool, *, load_labels: bool, only_host_labels: bool, on_error: OnError, ) -> None: section.section_step("Analyse discovered host labels") host_labels = analyse_node_labels( host_name=host_name, ipaddress=ipaddress, parsed_sections_broker=parsed_sections_broker, load_labels=load_labels, save_labels=True, on_error=on_error, ) count = len(host_labels.new) if host_labels.new else ( "no new" if only_new else "no") section.section_success(f"Found {count} host labels") if only_host_labels: return section.section_step("Analyse discovered services") service_result = analyse_discovered_services( host_name=host_name, ipaddress=ipaddress, parsed_sections_broker=parsed_sections_broker, run_plugin_names=run_plugin_names, only_new=only_new, on_error=on_error, ) # TODO (mo): for the labels the corresponding code is in _host_labels. # We should put the persisting in one place. autochecks.save_autochecks_file(host_name, service_result.present) new_per_plugin = Counter(s.check_plugin_name for s in service_result.new) for name, count in sorted(new_per_plugin.items()): console.verbose("%s%3d%s %s\n" % (tty.green + tty.bold, count, tty.normal, name)) count = len(service_result.new) if service_result.new else ( "no new" if only_new else "no") section.section_success(f"Found {count} services") for detail in check_parsing_errors( parsed_sections_broker.parsing_errors()).details: console.warning(detail)
def _prepare_check_command(command_spec: CheckCommandArguments, hostname: HostName, description: Optional[ServiceName]) -> str: """Prepares a check command for execution by Checkmk In case a list is given it quotes the single elements. It also prepares password store entries for the command line. These entries will be completed by the executed program later to get the password from the password store. """ passwords: List[Tuple[str, str, str]] = [] formated: List[str] = [] stored_passwords = cmk.utils.password_store.load() for arg in command_spec: if isinstance(arg, (int, float)): formated.append("%s" % arg) elif isinstance(arg, str): formated.append(cmk.utils.quote_shell_string(arg)) elif isinstance(arg, tuple) and len(arg) == 3: pw_ident, preformated_arg = arg[1:] try: password = stored_passwords[pw_ident] except KeyError: if hostname and description: descr = ' used by service "%s" on host "%s"' % ( description, hostname) elif hostname: descr = ' used by host host "%s"' % (hostname) else: descr = "" console.warning( 'The stored password "%s"%s does not exist (anymore).' % (pw_ident, descr)) password = "******" pw_start_index = str(preformated_arg.index("%s")) formated.append( cmk.utils.quote_shell_string(preformated_arg % ("*" * len(password)))) passwords.append((str(len(formated)), pw_start_index, pw_ident)) else: raise MKGeneralException("Invalid argument for command line: %r" % (arg, )) if passwords: formated = [ "--pwstore=%s" % ",".join(["@".join(p) for p in passwords]) ] + formated return " ".join(formated)
def do_restore(tarname): # type: (str) -> None console.verbose("Restoring from '%s'...\n", tarname) if not os.path.exists(tarname): raise MKGeneralException("Unable to restore: File does not exist") for name, path, canonical_name, descr, is_dir in backup_paths(): absdir = os.path.abspath(path) if is_dir: basedir = absdir filename = "." if os.path.exists(absdir): console.verbose(" Deleting old contents of '%s'\n", absdir) # The path might point to a symbalic link. So it is no option # to call shutil.rmtree(). We must delete just the contents for f in os.listdir(absdir): if f not in ['.', '..']: try: p = absdir + "/" + f if os.path.isdir(p): shutil.rmtree(p) else: os.remove(p) except Exception as e: console.warning(" Cannot delete %s: %s", p, e) else: basedir = os.path.dirname(absdir) filename = os.path.basename(absdir) canonical_path = basedir + "/" + canonical_name if os.path.exists(canonical_path): console.verbose(" Deleting old version of '%s'\n", canonical_path) os.remove(canonical_path) if not os.path.exists(basedir): console.verbose(" Creating directory %s\n", basedir) os.makedirs(basedir) console.verbose(" Extracting %s (%s)\n", descr, absdir) tar = tarfile.open(tarname, "r:gz") if is_dir: subtar = tarfile.open(fileobj=tar.extractfile(name + ".tar")) if filename == ".": subtar.extractall(basedir) elif filename in subtar.getnames(): subtar.extract(filename, basedir) subtar.close() elif filename in tar.getnames(): tar.extract(filename, basedir) tar.close() console.verbose("Successfully restored backup.\n")
def warn_about_network_ports(old_site_id: SiteId, new_site_id: SiteId) -> None: if not Path("/omd/sites", old_site_id).exists(): return # Site was not copied logger.info("") warning( "Network port configuration may need your attention\n\n" "It seems like you copied an existing site. In case you plan to use both on the same " "system, you may have to review the network port configuration of your sites. Two sites" "with the same configuration may cause network port conflicts." "For example if you enabled livestatus to listen via TCP or enabled the Event Console " "to listen for incoming Syslog messages or SNMP traps, you may have to update the " "configuration in one of the sites to resolve the conflicts.\n")
def warn_about_renamed_remote_site(old_site_id: SiteId, new_site_id: SiteId) -> None: """Warn user about central site that needs to be updated manually Detect whether or not this is a remote site and issue a warning to let the user known""" if not is_wato_slave_site(): return logger.info("") warning( "You renamed a distributed remote site.\n\nTo make your distributed " "setup work again, you will have to update the \"Distributed Monitoring\" " "configuration in your central site.\n")
def warn_about_configs_to_review(old_site_id: SiteId, new_site_id: SiteId) -> None: logger.info("") warning( "Some configs may need to be reviewed\n\n" "Parts of the site configuration cannot be migrated automatically. The following\n" "parts of the configuration may have to be reviewed and adjusted manually:\n\n" "- Custom bookmarks (in users bookmark lists)\n" "- Hard coded site filters in custom dashboards, views, reports\n" "- Path in rrdcached journal files\n" "- NagVis maps or custom NagVis backend settings\n" "- Notification rule \"site\" conditions\n" "- Event Console rule \"site\" conditions\n" "- \"site\" field in \"Agent updater (Linux, Windows, Solaris)\" rules (CEE/CME only)\n" "- Alert handler rule \"site\" conditions (CEE/CME only)\n")
def _extract_inventory_plugins(inf_info: Dict[InventoryPluginNameStr, InventoryInfo],) -> None: for plugin_name, plugin_info in sorted(inv_info.items()): try: agent_based_register.add_inventory_plugin( create_inventory_plugin_from_legacy( plugin_name, plugin_info, # count inherited extra sections from check plugin: len(config.check_info.get(plugin_name, {}).get("extra_sections", [])), )) except NotImplementedError: msg = config.AUTO_MIGRATION_ERR_MSG % ('inventory', plugin_name) if cmk.utils.debug.enabled(): raise MKGeneralException(msg) console.warning(msg)
def _do_inv_for_realhost( host_config: config.HostConfig, ipaddress: Optional[HostAddress], *, multi_host_sections: MultiHostSections, run_only_plugin_names: Optional[Set[InventoryPluginName]], ) -> InventoryTrees: tree_aggregator = _TreeAggregator() _set_cluster_property(tree_aggregator.trees.inventory, host_config) section.section_step("Executing inventory plugins") for inventory_plugin in agent_based_register.iter_all_inventory_plugins(): if run_only_plugin_names and inventory_plugin.name not in run_only_plugin_names: continue kwargs = multi_host_sections.get_section_kwargs( HostKey(host_config.hostname, ipaddress, SourceType.HOST), inventory_plugin.sections, ) if not kwargs: console.vverbose(" %s%s%s%s: skipped (no data)\n", tty.yellow, tty.bold, inventory_plugin.name, tty.normal) continue # Inventory functions can optionally have a second argument: parameters. # These are configured via rule sets (much like check parameters). if inventory_plugin.inventory_ruleset_name is not None: kwargs["params"] = host_config.inventory_parameters( str(inventory_plugin.inventory_ruleset_name) ) # TODO (mo): keep type! exception = tree_aggregator.aggregate_results( inventory_plugin.inventory_function(**kwargs), inventory_plugin.name, ) if exception: console.warning(" %s%s%s%s: failed: %s", tty.red, tty.bold, inventory_plugin.name, tty.normal, exception) else: console.verbose(" %s%s%s%s", tty.green, tty.bold, inventory_plugin.name, tty.normal) console.vverbose(": ok\n") console.verbose("\n") tree_aggregator.trees.inventory.normalize_nodes() tree_aggregator.trees.status_data.normalize_nodes() return tree_aggregator.trees
def _do_inv_for_realhost( host_config: config.HostConfig, ipaddress: Optional[HostAddress], *, parsed_sections_broker: ParsedSectionsBroker, run_plugin_names: Container[InventoryPluginName], ) -> InventoryTrees: tree_aggregator = TreeAggregator() _set_cluster_property(tree_aggregator.trees.inventory, host_config) section.section_step("Executing inventory plugins") for inventory_plugin in agent_based_register.iter_all_inventory_plugins(): if inventory_plugin.name not in run_plugin_names: continue for source_type in (SourceType.HOST, SourceType.MANAGEMENT): kwargs = get_section_kwargs( parsed_sections_broker, HostKey(host_config.hostname, ipaddress, source_type), inventory_plugin.sections, ) if not kwargs: console.vverbose(" %s%s%s%s: skipped (no data)\n", tty.yellow, tty.bold, inventory_plugin.name, tty.normal) continue # Inventory functions can optionally have a second argument: parameters. # These are configured via rule sets (much like check parameters). if inventory_plugin.inventory_ruleset_name is not None: kwargs["params"] = host_config.inventory_parameters( inventory_plugin.inventory_ruleset_name) exception = tree_aggregator.aggregate_results( inventory_plugin.inventory_function(**kwargs), ) if exception: console.warning(" %s%s%s%s: failed: %s", tty.red, tty.bold, inventory_plugin.name, tty.normal, exception) else: console.verbose(" %s%s%s%s", tty.green, tty.bold, inventory_plugin.name, tty.normal) console.vverbose(": ok\n") console.verbose("\n") tree_aggregator.trees.inventory.normalize_nodes() tree_aggregator.trees.status_data.normalize_nodes() return tree_aggregator.trees
def aggregate_results( self, inventory_generator: InventoryResult, plugin_name: InventoryPluginName, ) -> None: try: inventory_items = list(inventory_generator) except Exception as exc: if cmk.utils.debug.enabled(): raise console.warning(f"Error in inventory plugin {plugin_name}: {exc}") return for item in inventory_items: if isinstance(item, Attributes): self._integrate_attributes(item) elif isinstance(item, TableRow): self._integrate_table_row(item) else: # can't happen raise NotImplementedError()
def _aggregate_inventory_results( inventory_generator: InventoryGenerator, inventory_tree: StructuredDataTree, status_data_tree: StructuredDataTree, ) -> None: try: inventory_items = list(inventory_generator) except Exception as exc: if cmk.utils.debug.enabled(): raise console.warning("Error in plugin: %s" % exc) return for item in inventory_items: if isinstance(item, Attributes): _integrate_attributes(item, inventory_tree, status_data_tree) elif isinstance(item, TableRow): _integrate_table_row(item, inventory_tree, status_data_tree) else: # can't happen raise NotImplementedError()
def get_sub_options( self, all_opts: Options ) -> Optional[Dict[OptionName, Union[Argument, int, bool]]]: if not self.sub_options: return None options: Dict[OptionName, Union[Argument, int, bool]] = {} for o, a in all_opts: for option in self.sub_options: if o not in option.options(): continue if option.is_deprecated_option(o): console.warning("%r is deprecated in favour of option %r", o, option.name()) if a and not option.takes_argument(): raise MKGeneralException("No argument to %s expected." % o) val: Union[Argument, bool] = a if not option.takes_argument(): if option.count: value = options.setdefault(option.name(), 0) if not isinstance(value, int): raise TypeError() options[option.name()] = value + 1 continue val = True else: if option.argument_conv: try: val = option.argument_conv(a) except ValueError: raise MKGeneralException("%s: Invalid argument" % o) options[option.name()] = val return options
def _commandline_inventory_on_host( *, host_config: config.HostConfig, run_plugin_names: Container[InventoryPluginName], selected_sections: SectionNameCollection, ) -> None: section.section_step("Inventorizing") inv_result = _inventorize_host( host_config=host_config, selected_sections=selected_sections, run_plugin_names=run_plugin_names, retentions_tracker=RetentionsTracker([]), ) for subresult in check_parsing_errors(errors=inv_result.parsing_errors): for line in subresult.details: console.warning(line) # TODO: inv_results.source_results is completely ignored here. # We should process the results to make errors visible on the console count_i = inv_result.trees.inventory.count_entries() count_s = inv_result.trees.status_data.count_entries() section.section_success(f"Found {count_i} inventory entries") section.section_success(f"Found {count_s} status entries") if not host_config.inventory_export_hooks: return section.section_step("Execute inventory export hooks") _run_inventory_export_hooks(host_config, inv_result.trees.inventory) count = len(host_config.inventory_export_hooks) section.section_success(f"Sucessfully ran {count} export hooks")
def _discover_plugins_services( *, check_plugin_name: CheckPluginName, host_key: HostKey, parsed_sections_broker: ParsedSectionsBroker, on_error: OnError, ) -> Iterator[AutocheckEntry]: # Skip this check type if is ignored for that host if config.service_ignored(host_key.hostname, check_plugin_name, None): console.vverbose(" Skip ignored check plugin name '%s'\n" % check_plugin_name) return check_plugin = agent_based_register.get_check_plugin(check_plugin_name) if check_plugin is None: console.warning(" Missing check plugin: '%s'\n" % check_plugin_name) return try: kwargs = get_section_kwargs(parsed_sections_broker, host_key, check_plugin.sections) except Exception as exc: if cmk.utils.debug.enabled() or on_error is OnError.RAISE: raise if on_error is OnError.WARN: console.warning(" Exception while parsing agent section: %s\n" % exc) return if not kwargs: return disco_params = config.get_discovery_parameters(host_key.hostname, check_plugin) if disco_params is not None: kwargs = {**kwargs, "params": disco_params} try: yield from ( AutocheckEntry( check_plugin_name=check_plugin.name, item=service.item, parameters=unwrap_parameters(service.parameters), # Convert from APIs ServiceLabel to internal ServiceLabel service_labels={ label.name: label.value for label in service.labels }, ) for service in check_plugin.discovery_function(**kwargs)) except Exception as e: if on_error is OnError.RAISE: raise if on_error is OnError.WARN: console.warning( " Exception in discovery function of check plugin '%s': %s" % (check_plugin.name, e))
def commandline_inventory( hostnames: List[HostName], *, selected_sections: SectionNameCollection, run_plugin_names: Container[InventoryPluginName] = EVERYTHING, ) -> None: store.makedirs(cmk.utils.paths.inventory_output_dir) store.makedirs(cmk.utils.paths.inventory_archive_dir) for hostname in hostnames: section.section_begin(hostname) try: host_config = config.HostConfig.make_host_config(hostname) inv_result = _inventorize_host( host_config=host_config, selected_sections=selected_sections, run_plugin_names=run_plugin_names, ) _run_inventory_export_hooks(host_config, inv_result.trees.inventory) # TODO: inv_results.source_results is completely ignored here. # We should process the results to make errors visible on the console _show_inventory_results_on_console(inv_result.trees) for detail in check_parsing_errors( errors=inv_result.parsing_errors).details: console.warning(detail) except Exception as e: if cmk.utils.debug.enabled(): raise section.section_error("%s" % e) finally: cmk.utils.cleanup.cleanup_globals()
def _discover_plugins_services( *, check_plugin_name: CheckPluginName, host_name: HostName, ipaddress: Optional[HostAddress], parsed_sections_broker: ParsedSectionsBroker, on_error: OnError, ) -> Iterator[Service]: # Skip this check type if is ignored for that host if config.service_ignored(host_name, check_plugin_name, None): console.vverbose(" Skip ignored check plugin name '%s'\n" % check_plugin_name) return check_plugin = agent_based_register.get_check_plugin(check_plugin_name) if check_plugin is None: console.warning(" Missing check plugin: '%s'\n" % check_plugin_name) return host_key = HostKey( host_name, ipaddress, SourceType.MANAGEMENT if check_plugin.name.is_management_name() else SourceType.HOST, ) try: kwargs = parsed_sections_broker.get_section_kwargs( host_key, check_plugin.sections) except Exception as exc: if cmk.utils.debug.enabled() or on_error is OnError.RAISE: raise if on_error is OnError.WARN: console.warning(" Exception while parsing agent section: %s\n" % exc) return if not kwargs: return disco_params = config.get_discovery_parameters(host_name, check_plugin) if disco_params is not None: kwargs["params"] = disco_params try: plugins_services = check_plugin.discovery_function(**kwargs) yield from _enriched_discovered_services(host_name, check_plugin.name, plugins_services) except Exception as e: if on_error is OnError.RAISE: raise if on_error is OnError.WARN: console.warning( " Exception in discovery function of check plugin '%s': %s" % (check_plugin.name, e))
def get_check_preview( *, host_name: HostName, max_cachefile_age: cmk.core_helpers.cache.MaxAge, use_cached_snmp_data: bool, on_error: OnError, ) -> Tuple[CheckPreviewTable, QualifiedDiscovery[HostLabel]]: """Get the list of service of a host or cluster and guess the current state of all services if possible""" config_cache = config.get_config_cache() host_config = config_cache.get_host_config(host_name) ip_address = None if host_config.is_cluster else config.lookup_ip_address( host_config) cmk.core_helpers.cache.FileCacheFactory.use_outdated = True cmk.core_helpers.cache.FileCacheFactory.maybe = use_cached_snmp_data parsed_sections_broker, _source_results = make_broker( config_cache=config_cache, host_config=host_config, ip_address=ip_address, mode=Mode.DISCOVERY, file_cache_max_age=max_cachefile_age, selected_sections=NO_SELECTION, fetcher_messages=(), force_snmp_cache_refresh=not use_cached_snmp_data, on_scan_error=on_error, ) host_labels = analyse_host_labels( host_config=host_config, ipaddress=ip_address, parsed_sections_broker=parsed_sections_broker, load_labels=True, save_labels=False, on_error=on_error, ) for detail in check_parsing_errors( parsed_sections_broker.parsing_errors()).details: console.warning(detail) grouped_services = _get_host_services( host_config, ip_address, parsed_sections_broker, on_error, ) with load_host_value_store(host_name, store_changes=False) as value_store_manager: table = [ _check_preview_table_row( host_config=host_config, ip_address=ip_address, service=service, check_source=check_source, parsed_sections_broker=parsed_sections_broker, found_on_nodes=found_on_nodes, value_store_manager=value_store_manager, ) for check_source, services_with_nodes in grouped_services.items() for service, found_on_nodes in services_with_nodes ] return table, host_labels
def _do_inv_for_realhost( host_config: config.HostConfig, *, parsed_sections_broker: ParsedSectionsBroker, run_plugin_names: Container[InventoryPluginName], retentions_tracker: RetentionsTracker, ) -> InventoryTrees: tree_aggregator = TreeAggregator() _set_cluster_property(tree_aggregator.trees.inventory, host_config) section.section_step("Executing inventory plugins") for inventory_plugin in agent_based_register.iter_all_inventory_plugins(): if inventory_plugin.name not in run_plugin_names: continue for host_key in (host_config.host_key, host_config.host_key_mgmt): kwargs = get_section_kwargs( parsed_sections_broker, host_key, inventory_plugin.sections, ) if not kwargs: console.vverbose( " %s%s%s%s: skipped (no data)\n", tty.yellow, tty.bold, inventory_plugin.name, tty.normal, ) continue # Inventory functions can optionally have a second argument: parameters. # These are configured via rule sets (much like check parameters). if inventory_plugin.inventory_ruleset_name is not None: kwargs = { **kwargs, "params": host_config.inventory_parameters( inventory_plugin.inventory_ruleset_name), } exception = tree_aggregator.aggregate_results( inventory_generator=inventory_plugin.inventory_function( **kwargs), retentions_tracker=retentions_tracker, raw_cache_info=parsed_sections_broker.get_cache_info( inventory_plugin.sections), is_legacy_plugin=inventory_plugin.module is None, ) if exception: console.warning( " %s%s%s%s: failed: %s", tty.red, tty.bold, inventory_plugin.name, tty.normal, exception, ) else: console.verbose(" %s%s%s%s", tty.green, tty.bold, inventory_plugin.name, tty.normal) console.vverbose(": ok\n") console.verbose("\n") return tree_aggregator.trees
def warning(text: str) -> None: g_configuration_warnings.append(text) console.warning("\n%s", text, stream=sys.stdout)
def test_warning(stream): console.warning(" hello ", stream=stream) assert read(stream) == console._format_warning(" hello ")
def _snmp_scan(host_config, on_error="ignore", for_inv=False, do_snmp_scan=True, for_mgmt_board=False): # type: (SNMPHostConfig, str, bool, bool, bool) -> Set[CheckPluginName] import cmk.base.inventory_plugins as inventory_plugins # pylint: disable=import-outside-toplevel # Make hostname globally available for scan functions. # This is rarely used, but e.g. the scan for if/if64 needs # this to evaluate if_disabled_if64_checks. check_api_utils.set_hostname(host_config.hostname) snmp_cache.initialize_single_oid_cache(host_config) console.vverbose(" SNMP scan:\n") if not config.get_config_cache().in_binary_hostlist(host_config.hostname, config.snmp_without_sys_descr): for oid, name in [(".1.3.6.1.2.1.1.1.0", "system description"), (".1.3.6.1.2.1.1.2.0", "system object")]: value = snmp.get_single_oid(host_config, oid, do_snmp_scan=do_snmp_scan) if value is None: raise MKSNMPError( "Cannot fetch %s OID %s. This might be OK for some bogus devices. " "In that case please configure the ruleset \"Hosts without system " "description OID\" to tell Check_MK not to fetch the system " "description and system object OIDs." % (name, oid)) else: # Fake OID values to prevent issues with a lot of scan functions console.vverbose(" Skipping system description OID " "(Set .1.3.6.1.2.1.1.1.0 and .1.3.6.1.2.1.1.2.0 to \"\")\n") snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.1.0", "") snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.2.0", "") if for_inv: these_plugin_names = [ name for name in inventory_plugins.inv_info if inventory_plugins.is_snmp_plugin(name) ] else: # TODO (mo): stop converting to string! these_plugin_names = [str(n) for n in config.registered_snmp_sections] found_plugins = set() # type: Set[CheckPluginName] for check_plugin_name in these_plugin_names: if config.service_ignored(host_config.hostname, check_plugin_name, None): continue detection_spec = _get_detection_spec_from_plugin_name(check_plugin_name, inventory_plugins.inv_info) if detection_spec is None: console.warning(" SNMP check %s: Could not detect specifications for plugin" % check_plugin_name) continue try: def oid_function(oid, default_value=None, cp_name=check_plugin_name): # type: (OID, Optional[DecodedString], Optional[CheckPluginName]) -> Optional[DecodedString] value = snmp.get_single_oid(host_config, oid, cp_name, do_snmp_scan=do_snmp_scan) return default_value if value is None else value if callable(detection_spec): result = detection_spec(oid_function) else: result = _evaluate_snmp_detection(oid_function, detection_spec) if result is not None and not isinstance(result, (str, bool)): if on_error == "warn": console.warning(" SNMP scan function of %s returns invalid type %s." % (check_plugin_name, type(result))) elif on_error == "raise": raise MKGeneralException("SNMP Scan aborted.") elif result: found_plugins.add(check_plugin_name) except MKGeneralException: # some error messages which we explicitly want to show to the user # should be raised through this raise except Exception: if on_error == "warn": console.warning(" Exception in SNMP scan function of %s" % check_plugin_name) elif on_error == "raise": raise _output_snmp_check_plugins("SNMP scan found", found_plugins) filtered = config.filter_by_management_board( host_config.hostname, found_plugins, for_mgmt_board, for_discovery=True, for_inventory=for_inv, ) _output_snmp_check_plugins("SNMP filtered check plugin names", filtered) snmp_cache.write_single_oid_cache(host_config) return filtered
def _snmp_scan(host_config, on_error="ignore", for_inv=False, do_snmp_scan=True, for_mgmt_board=False): # type: (SNMPHostConfig, str, bool, bool, bool) -> Set[CheckPluginName] import cmk.base.inventory_plugins as inventory_plugins # pylint: disable=import-outside-toplevel # Make hostname globally available for scan functions. # This is rarely used, but e.g. the scan for if/if64 needs # this to evaluate if_disabled_if64_checks. check_api_utils.set_hostname(host_config.hostname) snmp_cache.initialize_single_oid_cache(host_config) console.vverbose(" SNMP scan:\n") if not config.get_config_cache().in_binary_hostlist( host_config.hostname, config.snmp_without_sys_descr): for oid, name in [(".1.3.6.1.2.1.1.1.0", "system description"), (".1.3.6.1.2.1.1.2.0", "system object")]: value = snmp.get_single_oid(host_config, oid, do_snmp_scan=do_snmp_scan) if value is None: raise MKSNMPError( "Cannot fetch %s OID %s. This might be OK for some bogus devices. " "In that case please configure the ruleset \"Hosts without system " "description OID\" to tell Check_MK not to fetch the system " "description and system object OIDs." % (name, oid)) else: # Fake OID values to prevent issues with a lot of scan functions console.vverbose( " Skipping system description OID " "(Set .1.3.6.1.2.1.1.1.0 and .1.3.6.1.2.1.1.2.0 to \"\")\n") snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.1.0", "") snmp_cache.set_single_oid_cache(".1.3.6.1.2.1.1.2.0", "") # TODO (mo): Assumption here is that inventory plugins are significantly fewer # than check plugins. We should pass an explicit list along, instead # of this flag. That way we would also get rid of the import above. if for_inv: section_names = [PluginName(n) for n in inventory_plugins.inv_info] these_sections = [ config.registered_snmp_sections[section_name] for section_name in section_names if section_name in config.registered_snmp_sections ] else: these_sections = list(config.registered_snmp_sections.values()) found_plugins = set() # type: Set[CheckPluginName] for section_plugin in these_sections: try: if _evaluate_snmp_detection( section_plugin.detect_spec, host_config, str(section_plugin.name), do_snmp_scan, ): found_plugins.add(str(section_plugin.name)) except MKGeneralException: # some error messages which we explicitly want to show to the user # should be raised through this raise except Exception: if on_error == "warn": console.warning(" Exception in SNMP scan function of %s" % section_plugin.name) elif on_error == "raise": raise _output_snmp_check_plugins("SNMP scan found", found_plugins) filtered = config.filter_by_management_board( host_config.hostname, found_plugins, for_mgmt_board, for_discovery=True, for_inventory=for_inv, ) _output_snmp_check_plugins("SNMP filtered check plugin names", filtered) snmp_cache.write_single_oid_cache(host_config) return filtered