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)
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)
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
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))
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))
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)))
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
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, )