def page(self): with table_element(title=self._table_title(), searchable=False, sortable=False) as table: for key_id, key in sorted(self.keys.items()): cert = crypto.load_certificate(crypto.FILETYPE_PEM, key["certificate"]) table.row() table.cell(_("Actions"), css="buttons") if self._may_edit_config(): delete_url = html.makeactionuri([("_delete", key_id)]) html.icon_button(delete_url, _("Delete this key"), "delete") download_url = html.makeuri_contextless([("mode", self.download_mode), ("key", key_id)]) html.icon_button(download_url, _("Download this key"), "download") table.cell(_("Description"), html.render_text(key["alias"])) table.cell(_("Created"), cmk.utils.render.date(key["date"])) table.cell(_("By"), html.render_text(key["owner"])) table.cell( _("Digest (MD5)"), html.render_text(cert.digest("md5").decode("ascii")))
def mk_eval(s): # type: (Union[bytes, Text]) -> Any try: d = base64.b64decode(s) return pickle.loads(d) if config.wato_legacy_eval else ast.literal_eval(six.ensure_text(d)) except Exception: raise MKGeneralException(_('Unable to parse provided data: %s') % html.render_text(repr(s)))
def _display_log(self, log): with table_element(css="data wato auditlog audit", limit=None, sortable=False, searchable=False) as table: for entry in log: table.row() table.cell(_("Time"), html.render_nobr( render.date_and_time(float(entry.time))), css="narrow") user = ( '<i>%s</i>' % _('internal')) if entry.user_id == '-' else entry.user_id table.cell(_("User"), html.render_text(user), css="nobreak narrow") table.cell(_("Object type"), entry.object_ref.object_type.name if entry.object_ref else "", css="narrow") table.cell(_("Object"), render_object_ref(entry.object_ref) or "", css="narrow") text = escaping.escape_text(entry.text).replace("\n", "<br>\n") table.cell(_("Summary"), text) if self._show_details: diff_text = entry.diff_text.replace( "\n", "<br>\n") if entry.diff_text else "" table.cell(_("Details"), diff_text)
def _show_entry_cells(self, table, ident, entry): table.cell(_("Title"), html.render_text(entry["title"])) table.cell(_("Conditions")) html.open_ul(class_="conditions") html.open_li() html.write( "%s: %s" % (_("Folder"), Folder.folder( entry["conditions"]["host_folder"]).alias_path())) html.close_li() html.close_ul() html.write(vs_conditions().value_to_text(entry["conditions"])) table.cell(_("Editable by")) if entry["owned_by"] is None: html.write_text( _("Administrators (having the permission " "\"Write access to all predefined conditions\")")) else: html.write_text(self._contact_group_alias(entry["owned_by"])) table.cell(_("Shared with")) if not entry["shared_with"]: html.write_text(_("Not shared")) else: html.write_text(", ".join( [self._contact_group_alias(g) for g in entry["shared_with"]]))
def mk_eval(s): try: if not config.wato_legacy_eval: return ast.literal_eval(base64.b64decode(s)) return pickle.loads(base64.b64decode(s)) except: raise MKGeneralException(_('Unable to parse provided data: %s') % html.render_text(repr(s)))
def page(self): html.open_div(id_="ldap") html.open_table() html.open_tr() html.open_td() html.begin_form("connection", method="POST") html.prevent_password_auto_completion() vs = self._valuespec() vs.render_input("connection", self._connection_cfg) vs.set_focus("connection") html.hidden_fields() html.end_form() html.close_td() html.open_td(style="padding-left:10px;vertical-align:top") html.h2(_('Diagnostics')) if not html.request.var('_test') or not self._connection_id: html.show_message( HTML( '<p>%s</p><p>%s</p>' % (_('You can verify the single parts of your ldap configuration using this ' 'dialog. Simply make your configuration in the form on the left side and ' 'hit the "Save & Test" button to execute the tests. After ' 'the page reload, you should see the results of the test here.'), _('If you need help during configuration or experience problems, please refer ' 'to the <a target="_blank" ' 'href="https://checkmk.com/checkmk_multisite_ldap_integration.html">' 'LDAP Documentation</a>.')))) else: connection = userdb.get_connection(self._connection_id) assert isinstance(connection, LDAPUserConnector) for address in connection.servers(): html.h3("%s: %s" % (_('Server'), address)) with table_element('test', searchable=False) as table: for title, test_func in self._tests(): table.row() try: state, msg = test_func(connection, address) except Exception as e: state = False msg = _('Exception: %s') % html.render_text("%s" % e) logger.exception("error testing LDAP %s for %s", title, address) if state: img = html.render_icon("success", _('Success')) else: img = html.render_icon("failed", _("Failed")) table.cell(_("Test"), title) table.cell(_("State"), img) table.cell(_("Details"), msg) connection.disconnect() html.close_td() html.close_tr() html.close_table() html.close_div()
def title(self): if self._topic and not self._search: heading = "%s - %s" % (_("Catalog of Check Plugins"), self._topic_title) elif self._search: heading = html.render_text("%s: %s" % (_("Check plugins matching"), self._search)) else: heading = _("Catalog of Check Plugins") return heading
def show_annotations(annotations, av_rawdata, what, avoptions, omit_service): annos_to_render = get_relevant_annotations(annotations, av_rawdata, what, avoptions) render_date = get_annotation_date_render_function(annos_to_render, avoptions) with table_element(title=_("Annotations"), omit_if_empty=True) as table: for (site_id, host, service), annotation in annos_to_render: table.row() table.cell("", css="buttons") anno_vars = [ ("anno_site", site_id), ("anno_host", host), ("anno_service", service or ""), ("anno_from", int(annotation["from"])), ("anno_until", int(annotation["until"])), ] edit_url = html.makeuri(anno_vars) html.icon_button(edit_url, _("Edit this annotation"), "edit") del_anno = [("_delete_annotation", "1")] # type: HTTPVariables delete_url = html.makeactionuri(del_anno + anno_vars) html.icon_button(delete_url, _("Delete this annotation"), "delete") if not omit_service: if "omit_host" not in avoptions["labelling"]: host_url = "view.py?" + html.urlencode_vars([("view_name", "hoststatus"), ("site", site_id), ("host", host)]) table.cell(_("Host"), html.render_a(host, host_url)) if what == "service": if service: service_url = "view.py?" + html.urlencode_vars([("view_name", "service"), ("site", site_id), ("host", host), ("service", service)]) # TODO: honor use_display_name. But we have no display names here... service_name = service table.cell(_("Service"), html.render_a(service_name, service_url)) else: table.cell(_("Service"), "") # Host annotation in service table table.cell(_("From"), render_date(annotation["from"]), css="nobr narrow") table.cell(_("Until"), render_date(annotation["until"]), css="nobr narrow") table.cell("", css="buttons") if annotation.get("downtime") is True: html.icon(_("This period has been reclassified as a scheduled downtime"), "downtime") elif annotation.get("downtime") is False: html.icon( _("This period has been reclassified as a not being a scheduled downtime"), "nodowntime") table.cell(_("Annotation"), html.render_text(annotation["text"])) table.cell(_("Author"), annotation["author"]) table.cell(_("Entry"), render_date(annotation["date"]), css="nobr narrow") if not cmk_version.is_raw_edition(): table.cell(_("Hide in report"), _("Yes") if annotation.get("hide_from_report") else _("No"))
def _add_cell( self, title: 'HTMLContent' = "", text: 'HTMLContent' = "", css: 'CSSSpec' = None, help_txt: Optional[str] = None, colspan: Optional[int] = None, sortable: bool = True, ): if isinstance(text, HTML): content = text else: content = html.render_text( str(text) if not isinstance(text, str) else text) htmlcode: HTML = content + HTML(html.drain()) if isinstance(title, HTML): header_title = title else: if title is None: title = "" header_title = html.render_text( str(title) if not isinstance(title, str) else title) if self.options["collect_headers"] is True: # small helper to make sorting introducion easier. Cells which contain # buttons are never sortable if css and 'buttons' in css and sortable: sortable = False self.headers.append( TableHeader(title=header_title, css=css, help_txt=help_txt, sortable=sortable)) current_row = self.rows[-1] assert isinstance(current_row, TableRow) current_row.cells.append(CellSpec(htmlcode, css, colspan))
def _display_log(self, log): with table_element(css="data wato auditlog audit", limit=None, sortable=False, searchable=False) as table: for t, linkinfo, user, _action, text in log: table.row() table.cell(_("Object"), self._render_logfile_linkinfo(linkinfo)) table.cell(_("Time"), html.render_nobr(render.date_and_time(float(t)))) user = ('<i>%s</i>' % _('internal')) if user == '-' else user table.cell(_("User"), html.render_text(user), css="nobreak") # This must not be attrencoded: The entries are encoded when writing to the log. table.cell(_("Change"), text.replace("\\n", "<br>\n"), css="fill")
def _show_entry_cells(self, table, ident, entry): table.cell(_("Title"), html.render_text(entry["title"])) table.cell(_("Editable by")) if entry["owned_by"] is None: html.write_text( _("Administrators (having the permission " "\"Write access to all passwords\")")) else: html.write_text(self._contact_group_alias(entry["owned_by"])) table.cell(_("Shared with")) if not entry["shared_with"]: html.write_text(_("Not shared")) else: html.write_text(", ".join([self._contact_group_alias(g) for g in entry["shared_with"]]))
def page(self): with table_element(title=self._table_title(), searchable=False, sortable=False) as table: for key_id, key in sorted(self.keys.items()): cert = crypto.load_certificate(crypto.FILETYPE_PEM, key["certificate"]) table.row() table.cell(_("Actions"), css="buttons") if self._may_edit_config(): message = self._delete_confirm_msg() if key["owner"] != config.user.id: message += _( "<br><b>Note</b>: this key has created by user <b>%s</b>" ) % key["owner"] delete_url = make_confirm_link( url=html.makeactionuri([("_delete", key_id)]), message=message, ) html.icon_button(delete_url, _("Delete this key"), "delete") download_url = makeuri_contextless( request, [("mode", self.download_mode), ("key", key_id)], ) html.icon_button(download_url, _("Download this key"), "download") table.cell(_("Description"), html.render_text(key["alias"])) table.cell(_("Created"), cmk.utils.render.date(key["date"])) table.cell(_("By"), html.render_text(key["owner"])) table.cell( _("Digest (MD5)"), html.render_text(cert.digest("md5").decode("ascii")))
def page(self): if not self._folder.may("read"): reason = self._folder.reason_why_may_not("read") if reason: html.show_message( html.render_icon("autherr", cssclass="authicon") + html.render_text(reason)) self._folder.show_locking_information() self._show_subfolders_of() if self._folder.may("read"): self._show_hosts() if not self._folder.has_hosts(): if self._folder.is_search_folder(): html.show_message(_("No matching hosts found.")) elif not self._folder.has_subfolders() and self._folder.may("write"): self._show_empty_folder_menu()
def title(self): if self._new: return _("Add LDAP connection") return _("Edit LDAP connection: %s") % html.render_text( self._connection_id)
def mk_eval(s: Union[bytes, str]) -> Any: try: return ast.literal_eval(ensure_str(base64.b64decode(s))) except Exception: raise MKGeneralException( _('Unable to parse provided data: %s') % html.render_text(repr(s)))
def title(self): if self._search: return _("Global settings matching '%s'") % html.render_text(self._search) return _("Global settings")
def _preview(self): # type: () -> None html.begin_form("preview", method="POST") self._preview_form() attributes = self._attribute_choices() # first line could be missing in situation of import error csv_reader = self._open_csv_file() if not csv_reader: return # don't try to show preview when CSV could not be read html.h2(_("Preview")) attribute_list = "<ul>%s</ul>" % "".join( ["<li>%s (%s)</li>" % a for a in attributes if a[0] is not None]) html.help( _("This list shows you the first 10 rows from your CSV file in the way the import is " "currently parsing it. If the lines are not splitted correctly or the title line is " "not shown as title of the table, you may change the import settings above and try " "again.") + "<br><br>" + _("The first row below the titles contains fields to specify which column of the " "CSV file should be imported to which attribute of the created hosts. The import " "progress is trying to match the columns to attributes automatically by using the " "titles found in the title row (if you have some). " "If you use the correct titles, the attributes can be mapped automatically. The " "currently available attributes are:") + attribute_list + _("You can change these assignments according to your needs and then start the " "import by clicking on the <i>Import</i> button above.")) # Wenn bei einem Host ein Fehler passiert, dann wird die Fehlermeldung zu dem Host angezeigt, so dass man sehen kann, was man anpassen muss. # Die problematischen Zeilen sollen angezeigt werden, so dass man diese als Block in ein neues CSV-File eintragen kann und dann diese Datei # erneut importieren kann. if self._has_title_line: try: headers = list(next(csv_reader)) except StopIteration: headers = [] # nope, there is no header else: headers = [] rows = list(csv_reader) # Determine how many columns should be rendered by using the longest column num_columns = max([len(r) for r in [headers] + rows]) with table_element(sortable=False, searchable=False, omit_headers=not self._has_title_line) as table: # Render attribute selection fields table.row() for col_num in range(num_columns): header = headers[col_num] if len(headers) > col_num else None table.cell(html.render_text(header)) attribute_varname = "attribute_%d" % col_num if html.request.var(attribute_varname): attribute_method = html.request.get_ascii_input_mandatory( "attribute_varname") else: attribute_method = self._try_detect_default_attribute( attributes, header) html.request.del_var(attribute_varname) html.dropdown("attribute_%d" % col_num, attributes, deflt=attribute_method, autocomplete="off") # Render sample rows for row in rows: table.row() for cell in row: table.cell(None, html.render_text(cell)) html.end_form()
def show(self): # type: () -> None filename = Path(cmk.utils.paths.omd_root).joinpath( 'var/dokuwiki/data/pages/sidebar.txt') html.open_form(id_="wiki_search", onsubmit="cmk.sidebar.wiki_search('%s');" % config.omd_site()) html.input(id_="wiki_search_field", type_="text", name="wikisearch") html.icon_button("#", _("Search"), "wikisearch", onclick="cmk.sidebar.wiki_search('%s');" % config.omd_site()) html.close_form() html.div('', id_="wiki_side_clear") start_ul = True ul_started = False try: title = None for line in filename.open(encoding="utf-8").readlines(): line = line.strip() if line == "": if ul_started: html.end_foldable_container() start_ul = True ul_started = False elif line.endswith(":"): title = line[:-1] elif line == "----": pass # html.br() elif line.startswith("*"): if start_ul: if title: html.begin_foldable_container("wikisnapin", title, True, title, indent=True) else: html.open_ul() start_ul = False ul_started = True erg = re.findall(r'\[\[(.*)\]\]', line) if len(erg) == 0: continue erg = erg[0].split('|') if len(erg) > 1: link = erg[0] name = erg[1] else: link = erg[0] name = erg[0] if link.startswith("http://") or link.startswith( "https://"): simplelink(name, link, "_blank") else: erg = name.split(':') if len(erg) > 0: name = erg[-1] else: name = erg[0] bulletlink( name, "/%s/wiki/doku.php?id=%s" % (config.omd_site(), link)) else: html.write_text(line) if ul_started: html.close_ul() except IOError: html.write_html( html.render_p( html.render_text( "To get a navigation menu, you have to create a ") + html.render_a("sidebar", href="/%s/wiki/doku.php?id=%s" % (config.omd_site(), _("sidebar")), target="main") + # html.render_text(" in your wiki first.")))
def parse_file(site, host_name, file_name, hidecontext=False): log_chunks: List[Dict[str, Any]] = [] try: chunk: Optional[Dict[str, Any]] = None lines = get_logfile_lines(site, host_name, file_name) if lines is None: return None # skip hash line. this doesn't exist in older files while lines and lines[0].startswith('#'): lines = lines[1:] for line in lines: line = line.strip() if line == '': continue if line[:3] == '<<<': # new chunk begins log_lines: List[Dict[str, Any]] = [] chunk = {'lines': log_lines} log_chunks.append(chunk) # New header line date, logtime, level = line[3:-3].split(' ') # Save level as integer to make it better comparable if level == 'CRIT': chunk['level'] = 2 elif level == 'WARN': chunk['level'] = 1 elif level == 'OK': chunk['level'] = 0 else: chunk['level'] = 0 # Gather datetime object # Python versions below 2.5 don't provide datetime.datetime.strptime. # Use the following instead: #chunk['datetime'] = datetime.datetime.strptime(date + ' ' + logtime, "%Y-%m-%d %H:%M:%S") chunk['datetime'] = datetime.datetime( *time.strptime(date + ' ' + logtime, "%Y-%m-%d %H:%M:%S")[0:5]) elif chunk: # else: not in a chunk?! # Data line line_display = line[2:] # Classify the line for styling if line[0] == 'W': line_level = 1 line_class = 'WARN' elif line[0] == 'u': line_level = 1 line_class = 'WARN' elif line[0] == 'C': line_level = 2 line_class = 'CRIT' elif line[0] == 'O': line_level = 0 line_class = 'OK' elif not hidecontext: line_level = 0 line_class = 'context' else: continue # ignore this line log_lines.append({ 'level': line_level, 'class': line_class, 'line': line_display }) except Exception as e: if config.debug: raise raise MKGeneralException( html.render_text( _("Cannot parse log file %s: %s") % (file_name, e))) return log_chunks
def do_log_ack(site, host_name, file_name): logs_to_ack = [] if not host_name and not file_name: # all logs on all hosts for this_site, this_host, logs in all_logs(): for int_filename in logs: file_display = form_file_to_ext(int_filename) logs_to_ack.append( (this_site, this_host, int_filename, file_display)) ack_msg = _('all logfiles on all hosts') elif host_name and not file_name: # all logs on one host for int_filename in logfiles_of_host(site, host_name): file_display = form_file_to_ext(int_filename) logs_to_ack.append((site, host_name, int_filename, file_display)) ack_msg = _('all logfiles of host %s') % host_name elif host_name and file_name: # one log on one host int_filename = form_file_to_int(file_name) logs_to_ack = [(site, host_name, int_filename, form_file_to_ext(int_filename))] ack_msg = _('the log file %s on host %s') % (file_name, host_name) else: for this_site, this_host, logs in all_logs(): file_display = form_file_to_ext(file_name) if file_name in logs: logs_to_ack.append( (this_site, this_host, file_name, file_display)) ack_msg = _('log file %s on all hosts') % file_name title = _("Acknowledge %s") % html.render_text(ack_msg) if host_name: breadcrumb = make_host_breadcrumb(host_name) else: breadcrumb = make_simple_page_breadcrumb(MegaMenuMonitoring, title) html.header(title, breadcrumb) html.begin_context_buttons() button_all_logfiles() if host_name: html.context_button(_("All Logfiles of Host"), html.makeuri([('file', '')])) if host_name and file_name: html.context_button(_("Back to Logfile"), html.makeuri([])) html.end_context_buttons() ack = html.request.var('_ack') if not html.confirm( _("Do you really want to acknowledge %s by <b>deleting</b> all stored messages?" ) % ack_msg): html.footer() return if not config.user.may("general.act"): html.h1(_('Permission denied'), class_=["error"]) html.div(_('You are not allowed to acknowledge %s') % ack_msg, class_=["error"]) html.footer() return # filter invalid values if ack != '1': raise MKUserError('_ack', _('Invalid value for ack parameter.')) for this_site, this_host, int_filename, display_name in logs_to_ack: try: acknowledge_logfile(this_site, this_host, int_filename, display_name) except Exception as e: html.show_error( _('The log file <tt>%s</tt> of host <tt>%s</tt> could not be deleted: %s.' ) % (display_name, this_host, e)) html.footer() return html.show_message('<b>%s</b><p>%s</p>' % (_('Acknowledged %s') % ack_msg, _('Acknowledged all messages in %s.') % ack_msg)) html.footer()
def _show_patterns(self): import cmk.gui.logwatch as logwatch collection = watolib.SingleRulesetRecursively("logwatch_rules") collection.load() ruleset = collection.get("logwatch_rules") html.h3(_('Logfile patterns')) if ruleset.is_empty(): html.open_div(class_="info") html.write_text('There are no logfile patterns defined. You may create ' 'logfile patterns using the <a href="%s">Rule Editor</a>.' % watolib.folder_preserving_link([ ('mode', 'edit_ruleset'), ('varname', 'logwatch_rules'), ])) html.close_div() # Loop all rules for this ruleset already_matched = False abs_rulenr = 0 for folder, rulenr, rule in ruleset.get_rules(): # Check if this rule applies to the given host/service if self._hostname: service_desc = self._get_service_description(self._hostname, "logwatch", self._item) # If hostname (and maybe filename) try match it rule_matches = rule.matches_host_and_item(watolib.Folder.current(), self._hostname, self._item, service_desc) else: # If no host/file given match all rules rule_matches = True html.begin_foldable_container("rule", "%s" % abs_rulenr, True, HTML("<b>Rule #%d</b>" % (abs_rulenr + 1)), indent=False) with table_element("pattern_editor_rule_%d" % abs_rulenr, sortable=False) as table: abs_rulenr += 1 # TODO: What's this? pattern_list = rule.value if isinstance(pattern_list, dict): pattern_list = pattern_list["reclassify_patterns"] # Each rule can hold no, one or several patterns. Loop them all here for state, pattern, comment in pattern_list: match_class = '' disp_match_txt = HTML('') match_img = '' if rule_matches: # Applies to the given host/service reason_class = 'reason' matched = re.search(pattern, self._match_txt) if matched: # Prepare highlighted search txt match_start = matched.start() match_end = matched.end() disp_match_txt = html.render_text(self._match_txt[:match_start]) \ + html.render_span(self._match_txt[match_start:match_end], class_="match")\ + html.render_text(self._match_txt[match_end:]) if not already_matched: # First match match_class = 'match first' match_img = 'match' match_title = _( 'This logfile pattern matches first and will be used for ' 'defining the state of the given line.') already_matched = True else: # subsequent match match_class = 'match' match_img = 'imatch' match_title = _( 'This logfile pattern matches but another matched first.') else: match_img = 'nmatch' match_title = _('This logfile pattern does not match the given string.') else: # rule does not match reason_class = 'noreason' match_img = 'nmatch' match_title = _('The rule conditions do not match.') table.row(css=reason_class) table.cell(_('Match')) html.icon(match_title, "rule%s" % match_img) cls = '' if match_class == 'match first': cls = 'svcstate state%d' % logwatch.level_state(state) table.cell(_('State'), logwatch.level_name(state), css=cls) table.cell(_('Pattern'), html.render_tt(pattern)) table.cell(_('Comment'), html.render_text(comment)) table.cell(_('Matched line'), disp_match_txt) table.row(fixed=True) table.cell(colspan=5) edit_url = watolib.folder_preserving_link([ ("mode", "edit_rule"), ("varname", "logwatch_rules"), ("rulenr", rulenr), ("host", self._hostname), ("item", ensure_str(watolib.mk_repr(self._item))), ("rule_folder", folder.path()), ]) html.icon_button(edit_url, _("Edit this rule"), "edit") html.end_foldable_container()