예제 #1
0
파일: profiling.py 프로젝트: n00rm/checkmk
def enable():
    # type: () -> None
    global _profile
    import cProfile
    _profile = cProfile.Profile()
    _profile.enable()
    console.verbose("Enabled profiling.\n")
예제 #2
0
    def walk(self,
             snmp_config,
             oid,
             check_plugin_name=None,
             table_base_oid=None,
             context_name=None):
        # type: (snmp_utils.SNMPHostConfig, str, Optional[str], Optional[str], Optional[str]) -> snmp_utils.SNMPRowInfo
        protospec = self._snmp_proto_spec(snmp_config)

        ipaddress = snmp_config.ipaddress
        if snmp_config.is_ipv6_primary:
            ipaddress = "[" + ipaddress + "]"

        portspec = self._snmp_port_spec(snmp_config)
        command = self._snmp_walk_command(snmp_config, context_name)
        command += [
            "-OQ", "-OU", "-On", "-Ot",
            "%s%s%s" % (protospec, ipaddress, portspec), oid
        ]
        console.vverbose("Running '%s'\n" % subprocess.list2cmdline(command))

        snmp_process = None
        exitstatus = None
        rowinfo = []  # type: snmp_utils.SNMPRowInfo
        try:
            snmp_process = subprocess.Popen(command,
                                            close_fds=True,
                                            stdin=open(os.devnull),
                                            stdout=subprocess.PIPE,
                                            stderr=subprocess.PIPE,
                                            encoding="utf-8")

            rowinfo = self._get_rowinfo_from_snmp_process(snmp_process)

        except MKTimeout:
            # On timeout exception try to stop the process to prevent child process "leakage"
            if snmp_process:
                os.kill(snmp_process.pid, signal.SIGTERM)
                snmp_process.wait()
            raise

        finally:
            # The stdout and stderr pipe are not closed correctly on a MKTimeout
            # Normally these pipes getting closed after p.communicate finishes
            # Closing them a second time in a OK scenario won't hurt neither..
            if snmp_process:
                exitstatus = snmp_process.wait()
                if snmp_process.stderr:
                    error = snmp_process.stderr.read()
                    snmp_process.stderr.close()
                if snmp_process.stdout:
                    snmp_process.stdout.close()

        if exitstatus:
            console.verbose(tty.red + tty.bold + "ERROR: " + tty.normal +
                            "SNMP error: %s\n" % six.ensure_str(error).strip())
            raise MKSNMPError(
                "SNMP Error on %s: %s (Exit-Code: %d)" %
                (ipaddress, six.ensure_str(error).strip(), exitstatus))
        return rowinfo
예제 #3
0
def update_dns_cache():
    # type: () -> UpdateDNSCacheResult
    failed = []

    ip_lookup_cache = _get_ip_lookup_cache()
    ip_lookup_cache.persist_on_update = False

    console.verbose("Cleaning up existing DNS cache...\n")
    _clear_ip_lookup_cache(ip_lookup_cache)

    console.verbose("Updating DNS cache...\n")
    for hostname, family in _get_dns_cache_lookup_hosts():
        console.verbose("%s (IPv%d)..." % (hostname, family))
        try:
            ip = lookup_ip_address(hostname, family)
            console.verbose("%s\n" % ip)

        except (MKTerminate, MKTimeout):
            # We should be more specific with the exception handler below, then we
            # could drop this special handling here
            raise

        except Exception as e:
            failed.append(hostname)
            console.verbose("lookup failed: %s\n" % e)
            if cmk.utils.debug.enabled():
                raise
            continue

    ip_lookup_cache.persist_on_update = True
    ip_lookup_cache.save_persisted()

    return len(ip_lookup_cache), failed
예제 #4
0
def enable():
    # type: () -> None
    global _profile
    import cProfile  # pylint: disable=import-outside-toplevel
    _profile = cProfile.Profile()
    _profile.enable()
    console.verbose("Enabled profiling.\n")
예제 #5
0
파일: decorator.py 프로젝트: n00rm/checkmk
        def wrapped_check_func(hostname, *args, **kwargs):
            # type: (HostName, Any, Any) -> int
            host_config = config.get_config_cache().get_host_config(hostname)
            exit_spec = host_config.exit_code_spec()

            status, infotexts, long_infotexts, perfdata = 0, [], [], []

            try:
                status, infotexts, long_infotexts, perfdata = check_func(
                    hostname, *args, **kwargs)

            except SystemExit:
                raise

            except MKTimeout:
                if _in_keepalive_mode():
                    raise
                else:
                    infotexts.append("Timed out")
                    status = max(status, cast(int, exit_spec.get("timeout",
                                                                 2)))

            except (MKAgentError, MKSNMPError, MKIPAddressLookupError) as e:
                infotexts.append("%s" % e)
                status = cast(int, exit_spec.get("connection", 2))

            except MKGeneralException as e:
                infotexts.append("%s" % e)
                status = max(status, cast(int, exit_spec.get("exception", 3)))

            except Exception:
                if cmk.utils.debug.enabled():
                    raise
                crash_output = cmk.base.crash_reporting.create_check_crash_dump(
                    hostname, check_plugin_name, None, False, None,
                    description, [])
                infotexts.append(
                    crash_output.replace("Crash dump:\n", "Crash dump:\\n"))
                status = max(status, cast(int, exit_spec.get("exception", 3)))

            # Produce the service check result output
            output_txt = "%s - %s" % (defines.short_service_state_name(status),
                                      ", ".join(infotexts))
            if perfdata:
                output_txt += " | %s" % " ".join(perfdata)
            if long_infotexts:
                output_txt = "%s\n%s" % (output_txt, "\n".join(long_infotexts))
            output_txt += "\n"

            if _in_keepalive_mode():
                keepalive.add_keepalive_active_check_result(
                    hostname, output_txt)
                console.verbose(output_txt.encode("utf-8"))
            else:
                console.output(output_txt.encode("utf-8"))

            return status
예제 #6
0
파일: snmp.py 프로젝트: stefan927/checkmk
def _execute_walks_for_dump(snmp_config, oids):
    for oid in oids:
        try:
            console.verbose("Walk on \"%s\"..." % oid)
            yield walk_for_export(snmp_config, oid)
        except Exception as e:
            console.error("Error: %s\n" % e)
            if cmk.utils.debug.enabled():
                raise
예제 #7
0
    def _create_tarfile(self):
        # type: () -> None
        filepaths = self._get_filepaths()

        console.verbose("Pack temporary files:\n")
        with tarfile.open(name=self.tarfile_path, mode='w:gz') as tar:
            for filepath in filepaths:
                console.verbose("  '%s'\n" % _get_short_filepath(filepath))
                tar.add(str(filepath), arcname=filepath.name)
예제 #8
0
파일: snmp.py 프로젝트: howie-f/checkmk
def _execute_walks_for_dump(snmp_config, oids):
    # type: (SNMPHostConfig, List[OID]) -> Iterable[SNMPRowInfo]
    for oid in oids:
        try:
            console.verbose("Walk on \"%s\"..." % oid)
            yield walk_for_export(snmp_config, oid)
        except Exception as e:
            console.error("Error: %s\n" % e)
            if cmk.utils.debug.enabled():
                raise
예제 #9
0
def cached_dns_lookup(hostname, family):
    # type: (HostName, int) -> Optional[str]
    cache = cmk.base.config_cache.get_dict("cached_dns_lookup")
    cache_id = hostname, family

    # Address has already been resolved in prior call to this function?
    try:
        return cache[cache_id]
    except KeyError:
        pass

    ip_lookup_cache = _get_ip_lookup_cache()

    cached_ip = ip_lookup_cache.get(cache_id)
    if cached_ip and config.use_dns_cache:
        cache[cache_id] = cached_ip
        return cached_ip

    host_config = config.get_config_cache().get_host_config(hostname)

    if host_config.is_no_ip_host:
        cache[cache_id] = None
        return None

    # Now do the actual DNS lookup
    try:
        ipa = socket.getaddrinfo(
            hostname, None, family == 4 and socket.AF_INET
            or socket.AF_INET6)[0][4][0]

        # Update our cached address if that has changed or was missing
        if ipa != cached_ip:
            console.verbose("Updating IPv%d DNS cache for %s: %s\n" %
                            (family, hostname, ipa))
            ip_lookup_cache.update_cache(cache_id, ipa)

        cache[cache_id] = ipa  # Update in-memory-cache
        return ipa

    except (MKTerminate, MKTimeout):
        # We should be more specific with the exception handler below, then we
        # could drop this special handling here
        raise

    except Exception as e:
        # DNS failed. Use cached IP address if present, even if caching
        # is disabled.
        if cached_ip:
            cache[cache_id] = cached_ip
            return cached_ip
        else:
            cache[cache_id] = None
            raise MKIPAddressLookupError(
                "Failed to lookup IPv%d address of %s via DNS: %s" %
                (family, hostname, e))
예제 #10
0
    def _cleanup_dump_folder(self):
        # type: () -> None
        dumps = sorted(
            [(dump.stat().st_mtime, dump) for dump in self.dump_folder.glob("*%s" % SUFFIX)],
            key=lambda t: t[0])[:-self._keep_num_dumps]

        console.verbose("Cleanup dump folder (remove old dumps, keep the last %s dumps):\n" %
                        self._keep_num_dumps)
        for _mtime, filepath in dumps:
            console.verbose("  '%s'\n" % _get_short_filepath(filepath))
            self._remove_file(filepath)
예제 #11
0
def _output_check_result(servicedesc, state, infotext, perftexts):
    # type: (ServiceName, ServiceState, ServiceDetails, List[str]) -> None
    if _show_perfdata:
        infotext_fmt = "%-56s"
        p = ' (%s)' % (" ".join(perftexts))
    else:
        p = ''
        infotext_fmt = "%s"

    console.verbose("%-20s %s%s" + infotext_fmt + "%s%s\n", servicedesc.encode('utf-8'), tty.bold,
                    tty.states[state], make_utf8(infotext.split('\n')[0]), tty.normal, make_utf8(p))
예제 #12
0
def _get_cached_snmpwalk(hostname, fetchoid):
    # type: (HostName, OID) -> Optional[SNMPRowInfo]
    path = _snmpwalk_cache_path(hostname, fetchoid)
    try:
        console.vverbose("  Loading %s from walk cache %s\n" % (fetchoid, path))
        return store.load_object_from_file(path)
    except Exception:
        if cmk.utils.debug.enabled():
            raise
        console.verbose("  Failed loading walk cache from %s. Continue without it.\n" % path)
        return None
예제 #13
0
 def _get_filepaths(self):
     # type: () -> List[Path]
     console.output("Collect diagnostics information:\n")
     filepaths = []
     for element in self.elements:
         filepath = element.add_or_get_file(self.tmp_dump_folder)
         if filepath is None:
             console.verbose("  %s: No informations\n" % element.ident)
             continue
         console.output("  %s\n" % element.description)
         filepaths.append(filepath)
     return filepaths
예제 #14
0
def service_outside_check_period(config_cache, hostname, description):
    # type: (config.ConfigCache, HostName, ServiceName) -> bool
    period = config_cache.check_period_of_service(hostname, description)
    if period is None:
        return False

    if cmk.base.core.check_timeperiod(period):
        console.vverbose("Service %s: timeperiod %s is currently active.\n",
                         six.ensure_str(description), period)
        return False

    console.verbose("Skipping service %s: currently not in timeperiod %s.\n",
                    six.ensure_str(description), period)
    return True
예제 #15
0
    def _create_tarfile(self):
        # type: () -> None
        filepaths = self._get_filepaths()

        console.verbose("Pack temporary files:\n")
        tarfile_filepath = self.dump_folder.joinpath(str(
            uuid.uuid4())).with_suffix(SUFFIX)
        with tarfile.open(name=tarfile_filepath, mode='w:gz') as tar:
            for filepath in filepaths:
                console.verbose("  '%s'\n" %
                                self._get_short_filepath(filepath))
                tar.add(str(filepath))

        console.output("Created diagnostics dump:\n")
        console.output("  '%s'\n" % self._get_short_filepath(tarfile_filepath))
예제 #16
0
파일: core.py 프로젝트: stefan927/checkmk
def try_get_activation_lock():
    global _restart_lock_fd
    # In some bizarr cases (as cmk -RR) we need to avoid duplicate locking!
    if config.restart_locking and _restart_lock_fd is None:
        lock_file = cmk.utils.paths.default_config_dir + "/main.mk"
        _restart_lock_fd = os.open(lock_file, os.O_RDONLY)
        # Make sure that open file is not inherited to monitoring core!
        fcntl.fcntl(_restart_lock_fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
        try:
            console.verbose("Waiting for exclusive lock on %s.\n" % lock_file,
                            stream=sys.stderr)
            fcntl.flock(
                _restart_lock_fd, fcntl.LOCK_EX |
                (config.restart_locking == "abort" and fcntl.LOCK_NB or 0))
        except Exception:
            return True
    return False
예제 #17
0
def _run_inventory_export_hooks(host_config, inventory_tree):
    import cmk.base.inventory_plugins as inventory_plugins
    hooks = host_config.inventory_export_hooks

    if not hooks:
        return

    console.step("Execute inventory export hooks")
    for hookname, params in hooks:
        console.verbose("Execute export hook: %s%s%s%s" %
                        (tty.blue, tty.bold, hookname, tty.normal))
        try:
            func = inventory_plugins.inv_export[hookname]["export_function"]
            func(host_config.hostname, params, inventory_tree.get_raw_tree())
        except Exception as e:
            if cmk.utils.debug.enabled():
                raise
            raise MKGeneralException("Failed to execute export hook %s: %s" %
                                     (hookname, e))
예제 #18
0
def precompile_hostchecks():
    console.verbose("Creating precompiled host check config...\n")
    config.PackedConfig().save()

    if not os.path.exists(cmk.utils.paths.precompiled_hostchecks_dir):
        os.makedirs(cmk.utils.paths.precompiled_hostchecks_dir)

    config_cache = config.get_config_cache()

    console.verbose("Precompiling host checks...\n")
    for host in config_cache.all_active_hosts():
        try:
            _precompile_hostcheck(config_cache, host)
        except Exception as e:
            if cmk.utils.debug.enabled():
                raise
            console.error("Error precompiling checks for host %s: %s\n" %
                          (host, e))
            sys.exit(5)
예제 #19
0
def _save_inventory_tree(hostname, inventory_tree):
    # type: (HostName, StructuredDataTree) -> Optional[StructuredDataTree]
    store.makedirs(cmk.utils.paths.inventory_output_dir)

    filepath = cmk.utils.paths.inventory_output_dir + "/" + hostname
    if inventory_tree.is_empty():
        # Remove empty inventory files. Important for host inventory icon
        if os.path.exists(filepath):
            os.remove(filepath)
        if os.path.exists(filepath + ".gz"):
            os.remove(filepath + ".gz")
        return None

    old_tree = StructuredDataTree().load_from(filepath)
    old_tree.normalize_nodes()
    if old_tree.is_equal(inventory_tree):
        console.verbose("Inventory was unchanged\n")
        return None

    if old_tree.is_empty():
        console.verbose("New inventory tree\n")
    else:
        console.verbose("Inventory tree has changed\n")
        old_time = os.stat(filepath).st_mtime
        arcdir = "%s/%s" % (cmk.utils.paths.inventory_archive_dir, hostname)
        store.makedirs(arcdir)
        os.rename(filepath, arcdir + ("/%d" % old_time))
    inventory_tree.save_to(cmk.utils.paths.inventory_output_dir, hostname)
    return old_tree
예제 #20
0
def _do_inv_for_realhost(host_config, sources, multi_host_sections, hostname,
                         ipaddress, inventory_tree, status_data_tree):
    # type: (config.HostConfig, data_sources.DataSources, Optional[data_sources.MultiHostSections], HostName, Optional[HostAddress], StructuredDataTree, StructuredDataTree) -> None
    for source in sources.get_data_sources():
        if isinstance(source, data_sources.SNMPDataSource):
            source.set_on_error("raise")
            source.set_do_snmp_scan(True)
            source.disable_data_source_cache()
            source.set_use_snmpwalk_cache(False)
            source.set_ignore_check_interval(True)
            source.set_check_plugin_name_filter(
                _gather_snmp_check_plugin_names_inventory)
            if multi_host_sections is not None:
                # Status data inventory already provides filled multi_host_sections object.
                # SNMP data source: If 'do_status_data_inv' is enabled there may be
                # sections for inventory plugins which were not fetched yet.
                source.enforce_check_plugin_names(None)
                host_sections = multi_host_sections.add_or_get_host_sections(
                    hostname, ipaddress, deflt=SNMPHostSections())
                source.set_fetched_check_plugin_names(
                    set(host_sections.sections))
                host_sections_from_source = source.run()
                host_sections.update(host_sections_from_source)

    if multi_host_sections is None:
        multi_host_sections = sources.get_host_sections()

    console.step("Executing inventory plugins")
    import cmk.base.inventory_plugins as inventory_plugins  # pylint: disable=import-outside-toplevel
    console.verbose("Plugins:")
    for section_name, plugin in inventory_plugins.sorted_inventory_plugins():
        section_content = multi_host_sections.get_section_content(
            hostname, ipaddress, section_name, for_discovery=False)
        if not section_content:  # section not present (None or [])
            # Note: this also excludes existing sections without info..
            continue

        if all([x in [[], {}, None] for x in section_content]):
            # Inventory plugins which get parsed info from related
            # check plugin may have more than one return value, eg
            # parse function of oracle_tablespaces returns ({}, {})
            continue

        console.verbose(" %s%s%s%s" %
                        (tty.green, tty.bold, section_name, tty.normal))

        # Inventory functions can optionally have a second argument: parameters.
        # These are configured via rule sets (much like check parameters).
        inv_function = plugin["inv_function"]
        kwargs = cmk.utils.misc.make_kwargs_for(
            inv_function,
            inventory_tree=inventory_tree,
            status_data_tree=status_data_tree)
        non_kwargs = set(
            cmk.utils.misc.getfuncargs(inv_function)) - set(kwargs)
        args = [section_content]
        if len(non_kwargs) == 2:
            args += [host_config.inventory_parameters(section_name)]
        inv_function(*args, **kwargs)
    console.verbose("\n")
예제 #21
0
    def get(self, snmp_config, oid, context_name=None):
        # type: (SNMPHostConfig, OID, Optional[ContextName]) -> Optional[RawValue]
        if oid.endswith(".*"):
            oid_prefix = oid[:-2]
            commandtype = "getnext"
        else:
            oid_prefix = oid
            commandtype = "get"

        protospec = self._snmp_proto_spec(snmp_config)
        ipaddress = snmp_config.ipaddress
        if snmp_config.is_ipv6_primary:
            ipaddress = "[" + ipaddress + "]"
        portspec = self._snmp_port_spec(snmp_config)
        command = (
            self._snmp_base_command(commandtype, snmp_config, context_name) + [
                "-On", "-OQ", "-Oe", "-Ot",
                "%s%s%s" % (protospec, ipaddress, portspec), oid_prefix
            ])

        console.vverbose("Running '%s'\n" % subprocess.list2cmdline(command))

        snmp_process = subprocess.Popen(
            command,
            close_fds=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            encoding="utf-8",
        )
        exitstatus = snmp_process.wait()
        if snmp_process.stderr is None or snmp_process.stdout is None:
            raise TypeError()
        if exitstatus:
            console.verbose(tty.red + tty.bold + "ERROR: " + tty.normal +
                            "SNMP error\n")
            console.verbose(snmp_process.stderr.read() + "\n")
            return None

        line = snmp_process.stdout.readline().strip()
        if not line:
            console.verbose("Error in response to snmpget.\n")
            return None

        parts = line.split("=", 1)
        if len(parts) != 2:
            return None
        item = parts[0]
        value = parts[1].strip()
        console.vverbose("SNMP answer: ==> [%s]\n" % value)
        if value.startswith('No more variables') or \
           value.startswith('End of MIB') or \
           value.startswith('No Such Object available') or \
           value.startswith('No Such Instance currently exists'):
            return None

        # In case of .*, check if prefix is the one we are looking for
        if commandtype == "getnext" and not item.startswith(oid_prefix + "."):
            return None

        return strip_snmp_value(value)
예제 #22
0
 def _create_dump_folders(self):
     # type: () -> None
     console.verbose("Create dump folders:\n")
     self.dump_folder.mkdir(parents=True, exist_ok=True)
     console.verbose("  '%s'\n" % _get_short_filepath(self.dump_folder))
     self.tmp_dump_folder.mkdir(parents=True, exist_ok=True)
     console.verbose("  '%s'\n" % _get_short_filepath(self.tmp_dump_folder))
예제 #23
0
    def _cleanup_tmp_dump_folder(self):
        # type: () -> None
        console.verbose("Remove temporary files:\n")
        for filepath in self.tmp_dump_folder.iterdir():
            console.verbose("  '%s'\n" % _get_short_filepath(filepath))
            self._remove_file(filepath)

        console.verbose("Remove temporary dump folder:\n")
        console.verbose("  '%s'\n" % _get_short_filepath(self.tmp_dump_folder))
        try:
            self.tmp_dump_folder.rmdir()
        except OSError as e:
            if e.errno != errno.ENOTEMPTY:
                raise
예제 #24
0
def do_backup(tarname):
    console.verbose("Creating backup file '%s'...\n", tarname)
    tar = tarfile.open(tarname, "w:gz")

    for name, path, canonical_name, descr, is_dir, in backup_paths():

        absdir = os.path.abspath(path)
        if os.path.exists(path):
            if is_dir:
                subtarname = name + ".tar"
                subfile = StringIO.StringIO()
                subtar = tarfile.open(mode="w", fileobj=subfile, dereference=True)
                subtar.add(path, arcname=".")
                subdata = subfile.getvalue()
            else:
                subtarname = canonical_name
                subdata = open(absdir).read()

            info = tarfile.TarInfo(subtarname)
            info.mtime = time.time()
            info.uid = 0
            info.gid = 0
            info.size = len(subdata)
            info.mode = 0o644
            info.type = tarfile.REGTYPE
            info.name = subtarname
            console.verbose("  Added %s (%s) with a size of %s\n", descr, absdir,
                            render.fmt_bytes(info.size))
            tar.addfile(info, StringIO.StringIO(subdata))

    tar.close()
    console.verbose("Successfully created backup.\n")
예제 #25
0
 def _get_filepaths(self):
     # type: () -> List[Path]
     console.verbose("Collect diagnostics files.\n")
     filepaths = []
     for element in self.elements:
         filepath = element.add_or_get_file(self.tmp_dump_folder)
         if filepath is None:
             console.verbose("  %s: No informations\n" % element.ident)
             continue
         console.verbose("  '%s'\n" % self._get_short_filepath(filepath))
         filepaths.append(filepath)
     return filepaths
예제 #26
0
def _do_snmpwalk_on(snmp_config, options, filename):
    # type: (SNMPHostConfig, SNMPWalkOptions, str) -> None
    console.verbose("%s:\n" % snmp_config.hostname)

    oids = oids_to_walk(options)

    with Path(filename).open("w", encoding="utf-8") as out:
        for rows in _execute_walks_for_dump(snmp_config, oids):
            for oid, value in rows:
                out.write(six.ensure_text("%s %s\n" % (oid, value)))
            console.verbose("%d variables.\n" % len(rows))

    console.verbose("Wrote fetched data to %s%s%s.\n" % (tty.bold, filename, tty.normal))
예제 #27
0
파일: snmp.py 프로젝트: stefan927/checkmk
def _do_snmpwalk_on(snmp_config, options, filename):
    console.verbose("%s:\n" % snmp_config.hostname)

    oids = oids_to_walk(options)

    with open(filename, "w") as out:
        for rows in _execute_walks_for_dump(snmp_config, oids):
            for oid, value in rows:
                out.write("%s %s\n" % (oid, value))
            console.verbose("%d variables.\n" % len(rows))

    console.verbose("Wrote fetched data to %s%s%s.\n" %
                    (tty.bold, filename, tty.normal))
예제 #28
0
    def get(self, snmp_config, oid, context_name=None):
        if oid.endswith(".*"):
            oid_prefix = oid[:-2]
            commandtype = "getnext"
        else:
            oid_prefix = oid
            commandtype = "get"

        protospec = self._snmp_proto_spec(snmp_config)
        ipaddress = snmp_config.ipaddress
        if snmp_config.is_ipv6_primary:
            ipaddress = "[" + ipaddress + "]"
        portspec = self._snmp_port_spec(snmp_config)
        command = self._snmp_base_command(commandtype, snmp_config, context_name) + \
                   [ "-On", "-OQ", "-Oe", "-Ot",
                     "%s%s%s" % (protospec, ipaddress, portspec),
                     oid_prefix ]

        console.vverbose("Running '%s'\n" % subprocess.list2cmdline(command))

        snmp_process = subprocess.Popen(command,
                                        close_fds=True,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)
        exitstatus = snmp_process.wait()
        if exitstatus:
            console.verbose(tty.red + tty.bold + "ERROR: " + tty.normal +
                            "SNMP error\n")
            console.verbose(snmp_process.stderr.read() + "\n")
            return None

        line = snmp_process.stdout.readline().strip()
        if not line:
            console.verbose("Error in response to snmpget.\n")
            return None

        item, value = line.split("=", 1)
        value = value.strip()
        console.vverbose("SNMP answer: ==> [%s]\n" % value)
        if value.startswith('No more variables') or value.startswith('End of MIB') \
           or value.startswith('No Such Object available') or value.startswith('No Such Instance currently exists'):
            value = None

        # In case of .*, check if prefix is the one we are looking for
        if commandtype == "getnext" and not item.startswith(oid_prefix + "."):
            value = None

        # Strip quotes
        if value and value.startswith('"') and value.endswith('"'):
            value = value[1:-1]
        return value
예제 #29
0
def do_check(hostname, ipaddress, only_check_plugin_names=None):
    # type: (HostName, Optional[HostAddress], Optional[List[CheckPluginName]]) -> Tuple[int, List[ServiceDetails], List[ServiceAdditionalDetails], List[Text]]
    cpu_tracking.start("busy")
    console.verbose("Check_MK version %s\n", six.ensure_str(cmk.__version__))

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

    exit_spec = host_config.exit_code_spec()

    status = 0  # type: ServiceState
    infotexts = []  # type: List[ServiceDetails]
    long_infotexts = []  # type: List[ServiceAdditionalDetails]
    perfdata = []  # type: List[Text]
    try:
        # In case of keepalive we always have an ipaddress (can be 0.0.0.0 or :: when
        # address is unknown). When called as non keepalive ipaddress may be None or
        # is already an address (2nd argument)
        if ipaddress is None and not host_config.is_cluster:
            ipaddress = ip_lookup.lookup_ip_address(hostname)

        item_state.load(hostname)

        sources = data_sources.DataSources(hostname, ipaddress)

        num_success, missing_sections = \
            _do_all_checks_on_host(sources, host_config, ipaddress, only_check_plugin_names)

        if _submit_to_core:
            item_state.save(hostname)

        for source in sources.get_data_sources():
            source_state, source_output, source_perfdata = source.get_summary_result_for_checking(
            )
            if source_output != "":
                status = max(status, source_state)
                infotexts.append("[%s] %s" % (source.id(), source_output))
                perfdata.extend(
                    [_convert_perf_data(p) for p in source_perfdata])

        if missing_sections and num_success > 0:
            missing_sections_status, missing_sections_infotext = \
                _check_missing_sections(missing_sections, exit_spec)
            status = max(status, missing_sections_status)
            infotexts.append(missing_sections_infotext)

        elif missing_sections:
            infotexts.append("Got no information from host")
            status = max(status, cast(int, exit_spec.get("empty_output", 2)))

        cpu_tracking.end()
        phase_times = cpu_tracking.get_times()
        total_times = phase_times["TOTAL"]
        run_time = total_times[4]

        infotexts.append("execution time %.1f sec" % run_time)
        if config.check_mk_perfdata_with_times:
            perfdata += [
                "execution_time=%.3f" % run_time,
                "user_time=%.3f" % total_times[0],
                "system_time=%.3f" % total_times[1],
                "children_user_time=%.3f" % total_times[2],
                "children_system_time=%.3f" % total_times[3],
            ]

            for phase, times in phase_times.items():
                if phase in ["agent", "snmp", "ds"]:
                    t = times[4] - sum(times[:4])  # real time - CPU time
                    perfdata.append("cmk_time_%s=%.3f" % (phase, t))
        else:
            perfdata.append("execution_time=%.3f" % run_time)

        return status, infotexts, long_infotexts, perfdata
    finally:
        if _checkresult_file_fd is not None:
            _close_checkresult_file()

        # "ipaddress is not None": At least when working with a cluster host it seems the ipaddress
        # may be None.  This needs to be understood in detail and cleaned up. As the InlineSNMP
        # stats feature is a very rarely used debugging feature, the analyzation and fix is
        # postponed now.
        if config.record_inline_snmp_stats \
           and ipaddress is not None \
           and host_config.snmp_config(ipaddress).is_inline_snmp_host:
            inline_snmp.save_snmp_stats()
예제 #30
0
def execute_check(config_cache, multi_host_sections, hostname, ipaddress,
                  check_plugin_name, item, params, description):
    # type: (config.ConfigCache, data_sources.MultiHostSections, HostName, Optional[HostAddress], CheckPluginName, Item, CheckParameters, ServiceName) -> Optional[bool]
    # Make a bit of context information globally available, so that functions
    # called by checks now this context
    check_api_utils.set_service(check_plugin_name, description)
    item_state.set_item_state_prefix(check_plugin_name, item)

    # Skip checks that are not in their check period
    period = config_cache.check_period_of_service(hostname, description)
    if period is not None:
        if not cmk.base.core.check_timeperiod(period):
            console.verbose(
                "Skipping service %s: currently not in timeperiod %s.\n",
                six.ensure_str(description), period)
            return None
        console.vverbose("Service %s: timeperiod %s is currently active.\n",
                         six.ensure_str(description), period)

    section_name = cmk.base.check_utils.section_name_of(check_plugin_name)

    dont_submit = False
    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,
                section_name,
                for_discovery=False,
                service_description=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

        # In case of SNMP checks but missing agent response, skip this check.
        # TODO: This feature predates the 'parse_function', and is not needed anymore.
        # # Special checks which still need to be called even with empty data
        # # may declare this.
        if not section_content and cmk.base.check_utils.is_snmp_check(check_plugin_name) \
           and not config.check_info[check_plugin_name]["handle_empty_info"]:
            return False

        check_function = config.check_info[check_plugin_name].get(
            "check_function")
        if check_function is None:
            check_function = lambda item, params, section_content: (
                3, 'UNKNOWN - Check not implemented')

        # Call the actual check function
        item_state.reset_wrapped_counters()

        raw_result = check_function(item, determine_check_params(params),
                                    section_content)
        result = sanitize_check_result(
            raw_result, cmk.base.check_utils.is_snmp_check(check_plugin_name))
        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",
                        six.ensure_str(description), e)
        dont_submit = True

    except MKTimeout:
        raise

    except Exception as e:
        if cmk.utils.debug.enabled():
            raise
        result = 3, cmk.base.crash_reporting.create_check_crash_dump(
            hostname, check_plugin_name, item,
            is_manual_check(hostname, check_plugin_name, item), params,
            description, section_content), []

    if not dont_submit:
        # Now add information about the age of the data in the agent
        # sections. This is in data_sources.g_agent_cache_info. For clusters we
        # use the oldest of the timestamps, of course.
        oldest_cached_at = None
        largest_interval = None

        def minn(a, b):
            # type: (Optional[int], Optional[int]) -> Optional[int]
            if a is None:
                return b
            if b is None:
                return a
            return min(a, b)

        for host_sections in multi_host_sections.get_host_sections().values():
            section_entries = host_sections.cache_info
            if section_name in section_entries:
                cached_at, cache_interval = section_entries[section_name]
                oldest_cached_at = minn(oldest_cached_at, cached_at)
                largest_interval = max(largest_interval, cache_interval)

        _submit_check_result(hostname,
                             description,
                             result,
                             cached_at=oldest_cached_at,
                             cache_interval=largest_interval)
    return True