示例#1
0
 def parse_line(self, line: bytes) -> Sequence[str]:
     line_str = ensure_str_with_fallback(
         line,
         encoding=self.encoding,
         fallback="latin-1",
     )
     if not self.nostrip:
         line_str = line_str.strip()
     return line_str.split(self.separator)
示例#2
0
 def parse_line(self, line: bytes) -> Sequence[str]:
     # ? ensure_str called on a bytes object with different possible encodings
     line_str = ensure_str_with_fallback(
         line,
         encoding=self.encoding,
         fallback="latin-1",
     )
     if not self.nostrip:
         line_str = line_str.strip()
     return line_str.split(self.separator)
示例#3
0
    def do_action(self, line: bytes) -> "ParserState":
        if not self.selected:
            return self

        if not self.section_header.nostrip:
            line = line.strip()

        self.host_sections.sections[self.section_header.name].append(
            ensure_str_with_fallback(
                line,
                encoding=self.section_header.encoding,
                fallback="latin-1",
            ).split(self.section_header.separator))
        return self
示例#4
0
def translate_piggyback_host(
    backedhost: HostName,
    translation: TranslationOptions,
    *,
    encoding_fallback: str,
) -> HostName:
    # To make it possible to match umlauts we need to change the hostname
    # to a unicode string which can then be matched with regexes etc.
    # We assume the incoming name is correctly encoded in UTF-8
    decoded_backedhost = ensure_str_with_fallback(
        backedhost,
        encoding="utf-8",
        fallback=encoding_fallback,
    )
    return ensure_str(translate_hostname(translation, decoded_backedhost))
示例#5
0
    def from_headerline(
        cls,
        line: bytes,
        translation: TranslationOptions,
        *,
        encoding_fallback: str,
    ) -> "PiggybackMarker":
        raw_host_name = ensure_str_with_fallback(
            line.strip()[4:-4],
            encoding='utf-8',
            fallback=encoding_fallback,
        )
        assert raw_host_name
        hostname = translate_hostname(translation, raw_host_name)

        # Protect Checkmk against unallowed host names. Normally source scripts
        # like agent plugins should care about cleaning their provided host names
        # up, but we need to be sure here to prevent bugs in Checkmk code.
        return cls(regex("[^%s]" % REGEX_HOST_NAME_CHARS).sub("_", hostname))
示例#6
0
    def from_headerline(
        cls,
        line: bytes,
        translation: TranslationOptions,
        *,
        encoding_fallback: str,
    ) -> "PiggybackMarker":
        # ? ensure_str called on a bytes object with different possible encodings
        raw_host_name = ensure_str_with_fallback(
            line.strip()[4:-4],
            encoding="utf-8",
            fallback=encoding_fallback,
        )
        assert raw_host_name
        hostname = translate_hostname(translation, raw_host_name)

        # Protect Checkmk against unallowed host names. Normally source scripts
        # like agent plugins should care about cleaning their provided host names
        # up, but we need to be sure here to prevent bugs in Checkmk code.
        # TODO: this should be moved into the HostName class, if it is ever created.
        return cls(
            HostName(
                regex("[^%s]" % REGEX_HOST_NAME_CHARS).sub("_", hostname)))
示例#7
0
    def __call__(self, line: bytes) -> ParserState:
        if not line.strip():
            return self

        try:
            if PiggybackParser.is_header(line):
                piggybacked_hostname = PiggybackParser.parse_header(
                    line,
                    self.translation,
                    encoding_fallback=self.encoding_fallback,
                )
                if piggybacked_hostname == self.hostname:
                    # Unpiggybacked "normal" host
                    return self
                return self.to_piggyback_section_parser(piggybacked_hostname)
            if HostSectionParser.is_footer(line):
                return self.to_noop_parser()
            if HostSectionParser.is_header(line):
                # Footer is optional.
                return self.to_host_section_parser(
                    HostSectionParser.parse_header(line))

            if not self.section_header.nostrip:
                line = line.strip()

            self.host_sections.sections[self.section_header.name].append(
                ensure_str_with_fallback(
                    line,
                    encoding=self.section_header.encoding,
                    fallback="latin-1",
                ).split(self.section_header.separator))
        except Exception:
            self._logger.warning("Ignoring invalid raw section: %r" % line,
                                 exc_info=True)
            return self.to_noop_parser()
        return self
示例#8
0
    def _parse_host_section(
        self,
        raw_data: AgentRawData,
        check_interval: int,
    ) -> AgentHostSections:
        """Split agent output in chunks, splits lines by whitespaces.

        Returns a HostSections() object.
        """
        hostname = self.hostname
        sections: AgentSections = {}
        # Unparsed info for other hosts. A dictionary, indexed by the piggybacked host name.
        # The value is a list of lines which were received for this host.
        piggybacked_raw_data: PiggybackRawData = {}
        piggybacked_hostname = None
        piggybacked_cached_at = int(time.time())
        # Transform to seconds and give the piggybacked host a little bit more time
        piggybacked_cache_age = int(1.5 * 60 * check_interval)

        # handle sections with option persist(...)
        persisted_sections: AgentPersistedSections = {}
        section_content: Optional[AgentSectionContent] = None
        section_options: Dict[str, Optional[str]] = {}
        agent_cache_info: SectionCacheInfo = {}
        separator: Optional[str] = None
        encoding = None
        for line in raw_data.split(b"\n"):
            line = line.rstrip(b"\r")
            stripped_line = line.strip()
            if stripped_line[:4] == b'<<<<' and stripped_line[-4:] == b'>>>>':
                piggybacked_hostname =\
                    AgentParser._get_sanitized_and_translated_piggybacked_hostname(stripped_line, hostname)

            elif piggybacked_hostname:  # processing data for an other host
                if stripped_line[:3] == b'<<<' and stripped_line[-3:] == b'>>>':
                    line = AgentParser._add_cached_info_to_piggybacked_section_header(
                        stripped_line, piggybacked_cached_at,
                        piggybacked_cache_age)
                piggybacked_raw_data.setdefault(piggybacked_hostname,
                                                []).append(line)

            # Found normal section header
            # section header has format <<<name:opt1(args):opt2:opt3(args)>>>
            elif stripped_line[:3] == b'<<<' and stripped_line[-3:] == b'>>>':
                section_name, section_options = AgentParser._parse_section_header(
                    stripped_line[3:-3])

                if section_name is None:
                    self._logger.warning("Ignoring invalid raw section: %r" %
                                         stripped_line)
                    section_content = None
                    continue
                section_content = sections.setdefault(section_name, [])

                raw_separator = section_options.get("sep")
                if raw_separator is None:
                    separator = None
                else:
                    separator = chr(int(raw_separator))

                # Split of persisted section for server-side caching
                raw_persist = section_options.get("persist")
                if raw_persist is not None:
                    until = int(raw_persist)
                    cached_at = int(time.time())  # Estimate age of the data
                    cache_interval = int(until - cached_at)
                    agent_cache_info[section_name] = (cached_at,
                                                      cache_interval)
                    persisted_sections[section_name] = (cached_at, until,
                                                        section_content)

                raw_cached = section_options.get("cached")
                if raw_cached is not None:
                    cache_times = list(map(int, raw_cached.split(",")))
                    agent_cache_info[section_name] = cache_times[
                        0], cache_times[1]

                # The section data might have a different encoding
                encoding = section_options.get("encoding")

            elif stripped_line != b'':
                if section_content is None:
                    continue

                raw_nostrip = section_options.get("nostrip")
                if raw_nostrip is None:
                    line = stripped_line

                decoded_line = ensure_str_with_fallback(
                    line,
                    encoding=("utf-8" if encoding is None else encoding),
                    fallback="latin-1")

                section_content.append(decoded_line.split(separator))

        return AgentHostSections(
            sections,
            agent_cache_info,
            piggybacked_raw_data,
            persisted_sections,
        )