def execute_automation_discovery( *, site_id: SiteId, args: Sequence[str], timeout=None, non_blocking_http=False) -> AutomationDiscoveryResponse: raw_response = check_mk_automation(site_id, "inventory", args, timeout=timeout, non_blocking_http=True) # This automation may be executed agains 1.6 remote sites. Be compatible to old structure # (counts, failed_hosts). if isinstance(raw_response, tuple) and len(raw_response) == 2: results = { hostname: DiscoveryResult( self_new=v[0], self_removed=v[1], self_kept=v[2], self_total=v[3], self_new_host_labels=v[4], self_total_host_labels=v[5], ) for hostname, v in raw_response[0].items() } for hostname, error_text in raw_response[1].items(): results[hostname].error_text = error_text return AutomationDiscoveryResponse(results=results) if isinstance(raw_response, dict): return AutomationDiscoveryResponse.deserialize(raw_response) raise NotImplementedError()
def _discover_services(self, request): mode = request.get("mode", "new") hostname = request.get("hostname") check_hostname(hostname, should_exist=True) host = watolib.Host.host(hostname) host_attributes = host.effective_attributes() if host.is_cluster(): # This is currently the only way to get some actual discovery statitics. # Start a dry-run -> Get statistics # Do an actual discovery on the nodes -> data is written try_result = watolib.check_mk_automation(host_attributes.get("site"), "try-inventory", ["@scan"] + [hostname]) new = 0 old = 0 for entry in try_result["check_table"]: if entry[0] == "new": new += 1 elif entry[0] == "old": old += 1 result = DiscoveryResult(self_new=new, self_kept=old, self_total=new + old) watolib.check_mk_automation(host_attributes.get("site"), "inventory", ["@scan", mode] + host.cluster_nodes()) else: response = execute_automation_discovery(site_id=host_attributes.get("site"), args=["@scan", mode, hostname]) result = response.results[hostname] if result.error_text: if not host.discovery_failed(): host.set_discovery_failed() raise MKUserError(None, _("Failed to discover %s: %s") % (hostname, result.error_text)) if host.discovery_failed(): host.clear_discovery_failed() if mode == "refresh": message = _("Refreshed check configuration of host [%s] with %d services") % ( hostname, result.self_total) watolib.add_service_change(host, "refresh-autochecks", message) else: message = _("Saved check configuration of host [%s] with %d services") % ( hostname, result.self_total) watolib.add_service_change(host, "set-autochecks", message) msg = _("Service discovery successful. Added %d, removed %d, kept %d, total %d services " "and %d new, %d total host labels") % ( result.self_new, result.self_removed, result.self_kept, result.self_total, result.self_new_host_labels, result.self_total_host_labels, ) return msg
def test__get_post_discovery_services(monkeypatch, grouped_services, mode, parameters_rediscovery, result_new_item_names, result_counts): def _get_service_description(_hostname, _check_plugin_name, item): return "Test Description %s" % item monkeypatch.setattr(config, "service_description", _get_service_description) result = DiscoveryResult() service_filters = discovery._ServiceFilters.from_settings( parameters_rediscovery) new_item_names = [ entry.service.item or "" for entry in discovery._get_post_discovery_services( "hostname", grouped_services, service_filters, result, mode, ) ] count_new, count_kept, count_removed = result_counts assert sorted(new_item_names) == sorted(result_new_item_names) assert result.self_new == count_new assert result.self_kept == count_kept assert result.self_removed == count_removed
def test_automation_discovery_not_existing_host(test_cfg, site): result = _execute_automation( site, "inventory", args=["@raiseerrors", "new", "xxxhost"], ) assert isinstance(result, results.DiscoveryResult) assert result.hosts == { "xxxhost": DiscoveryResult( clustered_new=0, clustered_old=0, clustered_vanished=0, diff_text=None, error_text="", self_kept=0, self_new=0, self_new_host_labels=0, self_removed=0, self_total=0, self_total_host_labels=0, ) }
def automation_discovery( *, config_cache: config.ConfigCache, host_config: config.HostConfig, mode: DiscoveryMode, service_filters: Optional[_ServiceFilters], on_error: OnError, use_cached_snmp_data: bool, max_cachefile_age: cmk.core_helpers.cache.MaxAge, ) -> DiscoveryResult: console.verbose(" Doing discovery with mode '%s'...\n" % mode) host_name = host_config.hostname result = DiscoveryResult() if host_name not in config_cache.all_active_hosts(): result.error_text = "" return result cmk.core_helpers.cache.FileCacheFactory.use_outdated = True cmk.core_helpers.cache.FileCacheFactory.maybe = use_cached_snmp_data try: # in "refresh" mode we first need to remove all previously discovered # checks of the host, so that _get_host_services() does show us the # new discovered check parameters. if mode is DiscoveryMode.REFRESH: result.self_removed += host_config.remove_autochecks( ) # this is cluster-aware! if host_config.is_cluster: ipaddress = None else: ipaddress = config.lookup_ip_address(host_config) parsed_sections_broker, _source_results = make_broker( config_cache=config_cache, host_config=host_config, ip_address=ipaddress, mode=Mode.DISCOVERY, selected_sections=NO_SELECTION, file_cache_max_age=max_cachefile_age, fetcher_messages=(), force_snmp_cache_refresh=not use_cached_snmp_data, on_scan_error=on_error, ) if mode is not DiscoveryMode.REMOVE: host_labels = analyse_host_labels( host_config=host_config, ipaddress=ipaddress, parsed_sections_broker=parsed_sections_broker, load_labels=True, save_labels=True, on_error=on_error, ) result.self_new_host_labels = len(host_labels.new) result.self_total_host_labels = len(host_labels.present) if mode is DiscoveryMode.ONLY_HOST_LABELS: # This is the result of a refactoring, and the following code was added # to ensure a compatible behaviour. I don't think it is particularly # sensible. We used to only compare service descriptions of old and new # services, so `make_object_diff` was always comparing two identical objects # if the mode was DiscoveryMode.ONLY_HOST_LABEL. # We brainlessly mimic that behaviour, for now. result.diff_text = make_object_diff(set(), set()) return result # Compute current state of new and existing checks services = _get_host_services( host_config, ipaddress, parsed_sections_broker, on_error=on_error, ) old_services = services.get("old", []) # Create new list of checks new_services = _get_post_discovery_services( host_name, services, service_filters or _ServiceFilters.accept_all(), result, mode) host_config.set_autochecks(new_services) # If old_services == new_services, make_object_diff will return # something along the lines of "nothing changed". # I guess this was written before discovered host labels were invented. result.diff_text = make_object_diff( {x.service.description for x in old_services}, {x.service.description for x in new_services}, ) except MKTimeout: raise # let general timeout through except Exception as e: if cmk.utils.debug.enabled(): raise result.error_text = str(e) result.self_total = result.self_new + result.self_kept return result
def discover_on_host( *, config_cache: config.ConfigCache, host_config: config.HostConfig, mode: DiscoveryMode, service_filters: Optional[_ServiceFilters], on_error: str, use_cached_snmp_data: bool, max_cachefile_age: int, ) -> DiscoveryResult: console.verbose(" Doing discovery with mode '%s'...\n" % mode) host_name = host_config.hostname result = DiscoveryResult() discovery_parameters = DiscoveryParameters( on_error=on_error, load_labels=(mode is not DiscoveryMode.REMOVE), save_labels=(mode is not DiscoveryMode.REMOVE), only_host_labels=(mode is DiscoveryMode.ONLY_HOST_LABELS), ) if host_name not in config_cache.all_active_hosts(): result.error_text = "" return result _set_cache_opts_of_checkers(use_cached_snmp_data=use_cached_snmp_data) try: # in "refresh" mode we first need to remove all previously discovered # checks of the host, so that _get_host_services() does show us the # new discovered check parameters. if mode is DiscoveryMode.REFRESH: result.self_removed += host_config.remove_autochecks() # this is cluster-aware! if host_config.is_cluster: ipaddress = None else: ipaddress = config.lookup_ip_address(host_config) parsed_sections_broker, _source_results = make_broker( config_cache=config_cache, host_config=host_config, ip_address=ipaddress, mode=Mode.DISCOVERY, selected_sections=NO_SELECTION, file_cache_max_age=max_cachefile_age, fetcher_messages=(), force_snmp_cache_refresh=not use_cached_snmp_data, on_scan_error=on_error, ) # Compute current state of new and existing checks services, host_labels = _get_host_services( host_config, ipaddress, parsed_sections_broker, discovery_parameters, ) old_services = services.get("old", []) # Create new list of checks new_services = _get_post_discovery_services(host_name, services, service_filters or _ServiceFilters.accept_all(), result, mode) host_config.set_autochecks(new_services) result.diff_text = make_object_diff( _make_services_audit_log_object([x.service for x in old_services]), _make_services_audit_log_object([x.service for x in new_services])) except MKTimeout: raise # let general timeout through except Exception as e: if cmk.utils.debug.enabled(): raise result.error_text = str(e) else: if mode is not DiscoveryMode.REMOVE: result.self_new_host_labels = len(host_labels.new) result.self_total_host_labels = len(host_labels.present) result.self_total = result.self_new + result.self_kept return result