Example #1
0
def test_mode_discover_marked_hosts(mocker):
    _patch_data_source(
        mocker,
        max_age=config.max_cachefile_age(),
    )  # inventory_max_cachefile_age
    # TODO: First configure auto discovery to make this test really work
    cmk.base.modes.check_mk.mode_discover_marked_hosts()
Example #2
0
def test_mode_discover_explicit_hosts_no_cache(mocker):
    _patch_data_source(mocker,
                       disabled=True,
                       max_age=config.max_cachefile_age())
    cmk.base.modes.check_mk.option_no_cache()  # --no-cache
    cmk.base.modes.check_mk.mode_discover({"discover": 1}, ["ds-test-host1"])
    assert Source.parse.call_count == 2  # type: ignore[attr-defined]
Example #3
0
def test_mode_dump_agent_explicit_host_no_cache(mocker, capsys):
    _patch_data_source(mocker,
                       disabled=True,
                       max_age=config.max_cachefile_age())
    cmk.base.modes.check_mk.option_no_cache()  # --no-cache
    cmk.base.modes.check_mk.mode_dump_agent(HostName("ds-test-host1"))
    assert Source.parse.call_count == 2  # type: ignore[attr-defined]
    assert "<<<check_mk>>>" in capsys.readouterr().out
Example #4
0
def commandline_discovery(
    arg_hostnames: Set[HostName],
    *,
    selected_sections: SectionNameCollection,
    run_plugin_names: Container[CheckPluginName],
    arg_only_new: bool,
    only_host_labels: bool = False,
) -> None:
    """Implementing cmk -I and cmk -II

    This is directly called from the main option parsing code.
    The list of hostnames is already prepared by the main code.
    If it is empty then we use all hosts and switch to using cache files.
    """
    config_cache = config.get_config_cache()

    on_error = OnError.RAISE if cmk.utils.debug.enabled() else OnError.WARN

    host_names = _preprocess_hostnames(arg_hostnames, config_cache,
                                       only_host_labels)

    mode = Mode.DISCOVERY if selected_sections is NO_SELECTION else Mode.FORCE_SECTIONS

    # Now loop through all hosts
    for host_name in sorted(host_names):
        host_config = config_cache.get_host_config(host_name)
        section.section_begin(host_name)
        try:
            ipaddress = config.lookup_ip_address(host_config)
            parsed_sections_broker, _results = make_broker(
                config_cache=config_cache,
                host_config=host_config,
                ip_address=ipaddress,
                mode=mode,
                selected_sections=selected_sections,
                file_cache_max_age=config.max_cachefile_age(),
                fetcher_messages=(),
                force_snmp_cache_refresh=False,
                on_scan_error=on_error,
            )
            _commandline_discovery_on_host(
                host_name,
                ipaddress,
                parsed_sections_broker,
                run_plugin_names,
                arg_only_new,
                load_labels=arg_only_new,
                only_host_labels=only_host_labels,
                on_error=on_error,
            )

        except Exception as e:
            if cmk.utils.debug.enabled():
                raise
            section.section_error("%s" % e)
        finally:
            cmk.utils.cleanup.cleanup_globals()
Example #5
0
def test_mode_discover_all_hosts(mocker):
    _patch_data_source(
        mocker,
        maybe=True,
        use_outdated=True,
        max_age=config.max_cachefile_age(),
    )
    cmk.base.modes.check_mk.mode_discover({"discover": 1}, [])
    active_real_hosts = config.get_config_cache().all_active_realhosts()
    assert Source.parse.call_count == (len(active_real_hosts) * 2)  # type: ignore[attr-defined]
Example #6
0
def test_mode_check_discovery_cached(mocker):
    _patch_data_source(
        mocker,
        max_age=config.max_cachefile_age(),
        use_outdated=True,
        maybe=True,
    )

    cmk.base.modes.check_mk.option_cache()
    assert cmk.base.modes.check_mk.mode_check_discovery(HostName("ds-test-host1")) == 1
    assert Source.parse.call_count == 2  # type: ignore[attr-defined]
Example #7
0
def test_mode_dump_agent_explicit_host_cache(mocker, capsys):
    _patch_data_source(
        mocker,
        max_age=config.max_cachefile_age(),
        maybe=True,
        use_outdated=True,
    )
    cmk.base.modes.check_mk.option_cache()
    cmk.base.modes.check_mk.mode_dump_agent("ds-test-host1")
    assert Source.parse.call_count == 2  # type: ignore[attr-defined]
    assert "<<<check_mk>>>" in capsys.readouterr().out
def _fixup_caching_info(source: Source) -> Source:
    if source.fetcher_type is not FetcherType.SNMP:
        # By default this is MaxAge.none(). For checking this is the same as max_cachefile_age(),
        # but:
        # During discovery, the allowed cache age is (by default) 120 seconds, such that the
        # discovery service won't steal data in the TCP case.
        # But we do want to see new services, so for SNMP we leave the cache age at zero.
        # For TCP, we ensure updated caches by triggering the "Check_MK" service whenever the
        # user manually triggers "Check_MK Discovery", but then use cached data during the actual
        # discovery
        source.file_cache_max_age = max_cachefile_age()
    return source
Example #9
0
def _patch_data_source(mocker, **kwargs):
    defaults = {
        "maybe": False,
        "use_outdated": False,
        "max_age": config.max_cachefile_age(),
        "disabled": False,
        "use_only_cache": False,
        "use_outdated_persisted_sections": False,
        "on_error": "raise",
    }
    defaults.update(kwargs)

    def parse(self, *args, callback, **kwargs):
        assert isinstance(self, Source), repr(self)

        file_cache = self._make_file_cache()

        assert file_cache.disabled == (
            True
            if isinstance(file_cache, NoCache)
            else defaults["disabled"]
            if isinstance(self, SNMPSource)
            else defaults["disabled"]
        ), repr(file_cache)

        assert file_cache.use_outdated == defaults["use_outdated"]
        assert file_cache.max_age == defaults["max_age"]

        if isinstance(self, TCPSource):
            assert self.use_only_cache == defaults["use_only_cache"]
        if isinstance(self, AgentSource):
            assert (
                self.use_outdated_persisted_sections == defaults["use_outdated_persisted_sections"]
            )

        elif isinstance(self, SNMPSource):
            assert self._on_snmp_scan_error == defaults["on_error"]

        result = callback(self, *args, **kwargs)
        if result.is_error():
            raise result.error
        return result

    mocker.patch.object(
        Source,
        "parse",
        autospec=True,
        side_effect=partial(parse, callback=Source.parse),
    )
Example #10
0
def test_automation_discovery_caching(raise_errors, scan, mocker):
    kwargs = {}
    kwargs.update(raise_errors[1])
    # The next options come from the call to `_set_cache_opts_of_checkers()`
    # in `AutomationDiscovery`.
    kwargs.update(
        use_outdated=True,
        max_age=config.max_cachefile_age(),
    )

    _patch_data_source(mocker, **kwargs)

    args = []
    if raise_errors[0] is not None:
        args.append(raise_errors[0])
    if scan is not None:
        args.append(scan)

    args += ["fixall", "ds-test-host1"]
    cmk.base.automations.check_mk.AutomationDiscovery().execute(args)
    assert Source.parse.call_count == 2  # type: ignore[attr-defined]
Example #11
0
def _discover_marked_host(
    *,
    config_cache: config.ConfigCache,
    host_config: config.HostConfig,
    autodiscovery_queue: _AutodiscoveryQueue,
    reference_time: float,
    oldest_queued: float,
) -> bool:
    host_name = host_config.hostname
    console.verbose(f"{tty.bold}{host_name}{tty.normal}:\n")

    if host_config.discovery_check_parameters is None:
        console.verbose("  failed: discovery check disabled\n")
        return False
    rediscovery_parameters = host_config.discovery_check_parameters.get(
        "inventory_rediscovery", {})

    reason = _may_rediscover(
        rediscovery_parameters=rediscovery_parameters,
        reference_time=reference_time,
        oldest_queued=oldest_queued,
    )
    if reason:
        console.verbose(f"  skipped: {reason}\n")
        return False

    result = automation_discovery(
        config_cache=config_cache,
        host_config=host_config,
        mode=DiscoveryMode(rediscovery_parameters.get("mode")),
        service_filters=_ServiceFilters.from_settings(rediscovery_parameters),
        on_error=OnError.IGNORE,
        use_cached_snmp_data=True,
        # autodiscovery is run every 5 minutes (see
        # omd/packages/check_mk/skel/etc/cron.d/cmk_discovery)
        # make sure we may use the file the active discovery check left behind:
        max_cachefile_age=config.max_cachefile_age(discovery=600),
    )
    if result.error_text is not None:
        # for offline hosts the error message is empty. This is to remain
        # compatible with the automation code
        console.verbose(
            f"  failed: {result.error_text or 'host is offline'}\n")
        # delete the file even in error case, otherwise we might be causing the same error
        # every time the cron job runs
        autodiscovery_queue.remove(host_name)
        return False

    something_changed = (result.self_new != 0 or result.self_removed != 0
                         or result.self_kept != result.self_total
                         or result.clustered_new != 0
                         or result.clustered_vanished != 0
                         or result.self_new_host_labels != 0)

    if not something_changed:
        console.verbose("  nothing changed.\n")
        activation_required = False
    else:
        console.verbose(
            f"  {result.self_new} new, {result.self_removed} removed, "
            f"{result.self_kept} kept, {result.self_total} total services "
            f"and {result.self_new_host_labels} new host labels. "
            f"clustered new {result.clustered_new}, clustered vanished "
            f"{result.clustered_vanished}")

        # Note: Even if the actual mark-for-discovery flag may have been created by a cluster host,
        #       the activation decision is based on the discovery configuration of the node
        activation_required = bool(rediscovery_parameters["activation"])

        # Enforce base code creating a new host config object after this change
        config_cache.invalidate_host_config(host_name)

        # Now ensure that the discovery service is updated right after the changes
        schedule_discovery_check(host_name)

    autodiscovery_queue.remove(host_name)

    return activation_required
Example #12
0
def active_check_discovery(
    host_name: HostName,
    ipaddress: Optional[HostAddress],
    *,
    # The next argument *must* remain optional for the DiscoCheckExecutor.
    #   See Also: `cmk.base.agent_based.checking.active_check_checking()`.
    fetcher_messages: Sequence[FetcherMessage] = (),
) -> ActiveCheckResult:

    # Note: '--cache' is set in core_cmc, nagios template or even on CL and means:
    # 1. use caches as default:
    #    - Set FileCacheFactory.maybe = True (set max_cachefile_age, else 0)
    #    - Set FileCacheFactory.use_outdated = True
    # 2. Then these settings are used to read cache file or not

    config_cache = config.get_config_cache()
    host_config = config_cache.get_host_config(host_name)

    params = host_config.discovery_check_parameters
    if params is None:
        params = host_config.default_discovery_check_parameters()
    rediscovery_parameters = params.get("inventory_rediscovery", {})

    discovery_mode = DiscoveryMode(rediscovery_parameters.get("mode"))

    # In case of keepalive discovery we always have an ipaddress. When called as non keepalive
    # ipaddress is always None
    if ipaddress is None and not host_config.is_cluster:
        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,
        fetcher_messages=fetcher_messages,
        selected_sections=NO_SELECTION,
        file_cache_max_age=config.max_cachefile_age(
            discovery=None if cmk.core_helpers.cache.FileCacheFactory.
            maybe else 0),
        force_snmp_cache_refresh=False,
        on_scan_error=OnError.RAISE,
    )

    host_labels = analyse_host_labels(
        host_config=host_config,
        ipaddress=ipaddress,
        parsed_sections_broker=parsed_sections_broker,
        load_labels=True,
        save_labels=False,
        on_error=OnError.RAISE,
    )
    services = _get_host_services(
        host_config,
        ipaddress,
        parsed_sections_broker,
        on_error=OnError.RAISE,
    )

    services_result, services_need_rediscovery = _check_service_lists(
        host_name=host_name,
        services_by_transition=services,
        params=params,
        service_filters=_ServiceFilters.from_settings(rediscovery_parameters),
        discovery_mode=discovery_mode,
    )

    host_labels_result, host_labels_need_rediscovery = _check_host_labels(
        host_labels,
        int(params.get("severity_new_host_label", 1)),
        discovery_mode,
    )

    parsing_errors_result = check_parsing_errors(
        parsed_sections_broker.parsing_errors())

    return ActiveCheckResult.from_subresults(
        services_result,
        host_labels_result,
        *check_sources(source_results=source_results, mode=Mode.DISCOVERY),
        parsing_errors_result,
        _schedule_rediscovery(
            host_config=host_config,
            need_rediscovery=(services_need_rediscovery
                              or host_labels_need_rediscovery)
            and parsing_errors_result.state == 0,
        ),
    )
Example #13
0
def test_mode_discover_explicit_hosts(mocker):
    # TODO: Is it correct that no cache is used here?
    _patch_data_source(mocker, max_age=config.max_cachefile_age())
    cmk.base.modes.check_mk.mode_discover({"discover": 1}, ["ds-test-host1"])
    assert Source.parse.call_count == 2  # type: ignore[attr-defined]
Example #14
0
@pytest.fixture
def without_inventory_plugins(monkeypatch):
    monkeypatch.setattr(cmk.base.api.agent_based.register, "iter_all_inventory_plugins", lambda: ())


# When called without hosts, it uses all hosts and defaults to using the data source cache
# When called with an explicit list of hosts the cache is not used by default, the option
# --cache enables it and --no-cache enforce never to use it
@pytest.mark.parametrize(
    ("hosts"),
    [
        (
            ["ds-test-host1"],
            {
                "max_age": config.max_cachefile_age(),
            },
        ),
        (
            ["ds-test-cluster1"],
            {
                "max_age": config.max_cachefile_age(),
            },
        ),
        ([], {}),
    ],
    ids=["host", "cluster", "empty"],
)
@pytest.mark.parametrize(
    ("cache"),
    [