def show_details(self, crash_info: CrashInfo, row) -> None: details = crash_info["details"] html.h3(_("Details"), class_="table") html.open_table(class_="data") _crash_row(_("Page"), details["page"], odd=False, legend=True) _crash_row(_("Request Method"), details.get("request_method", _("Unknown"))) html.open_tr(class_="data even0") html.td(_("HTTP Parameters"), class_="left") html.open_td() debug_vars(html, html.request, vars_=details["vars"], hide_with_mouse=False) html.close_td() html.close_tr() _crash_row(_("Referer"), details.get("referer", _("Unknown"))) _crash_row(_("Username"), details["username"], odd=False) _crash_row(_("User Agent"), details["user_agent"]) _crash_row(_("Mobile GUI"), details["is_mobile"], odd=False) _crash_row(_("SSL"), details["is_ssl_request"]) _crash_row(_("Language"), details["language"], odd=False) html.close_table()
def show_job_class_infos(cls, job_class_infos, **kwargs): """Renders all jobs from the job_class_infos in a single multi-table""" html.open_table(css="job_table data") for job_class, jobs_info in sorted(job_class_infos.items(), key=lambda x: x[0].gui_title()): html.open_tr() html.open_td(colspan=len(cls.get_headers())) html.h3(job_class.gui_title()) html.close_td() html.close_tr() if not jobs_info: html.open_tr() html.open_td(colspan=len(cls.get_headers())) html.div(_("No entries"), css="info") html.close_td() html.close_tr() continue cls.show_job_row_headers() odd = "even" for job_id, job_status in sorted(jobs_info.items(), key=lambda x: x[1]["started"], reverse=True): cls.render_job_row(job_id, job_status, odd, **kwargs) odd = "even" if odd == "odd" else "odd"
def _show_command_form(datasource: ABCDataSource, rows: Rows) -> None: what = datasource.infos[0] html.javascript( """ $(document).ready(function() { $('.command_group').has('x').trigger('expand'); $('x').children().css('background-color', '#f84'); }); """ ) one_shown = False html.open_div(**{"data-role": "collapsible-set"}) for command_class in command_registry.values(): command = command_class() if what in command.tables and user.may(command.permission.name): html.open_div(class_=["command_group"], **{"data-role": "collapsible"}) html.h3(command.title) html.open_p() html.begin_form("actions") html.hidden_field("_do_actions", "yes") html.hidden_field("actions", "yes") command.render(what) html.hidden_fields() html.end_form() html.close_p() html.close_div() one_shown = True html.close_div() if not one_shown: html.write_text(_("No commands are possible in this view"))
def _render_manpage_list(titles, manpage_list, path_comp, heading): def translate(t): return titles.get(t, t) html.h3(heading) with table_element(searchable=False, sortable=False, css="check_catalog") as table: for entry in sorted(manpage_list, key=lambda x: x["title"]): if not isinstance(entry, dict): continue table.row() url = makeuri( request, [ ("mode", "check_manpage"), ("check_type", entry["name"]), ("back", makeuri(request, [])), ], ) table.cell(_("Type of Check"), HTMLWriter.render_a(entry["title"], href=url), css=["title"]) table.cell(_("Plugin Name"), HTMLWriter.render_tt(entry["name"]), css=["name"]) table.cell(_("Agents"), ", ".join(map(translate, sorted(entry["agents"]))), css=["agents"])
def show_log_list(): title = _("All problematic logfiles") breadcrumb = make_simple_page_breadcrumb( mega_menu_registry.menu_monitoring(), title) make_header(html, title, breadcrumb, _log_list_page_menu(breadcrumb)) if request.has_var("_ack") and not request.var("_do_actions") == _("No"): do_log_ack(site=None, host_name=None, file_name=None) return for site, host_name, logs in all_logs(): if not logs: continue all_logs_empty = not any( parse_file(site, host_name, file_name) for file_name in logs) if all_logs_empty: continue # Logfile vanished html.h3( HTMLWriter.render_a( host_name, href=makeuri( request, [("site", site), ("host", host_name)], ), ), class_="table", ) list_logs(site, host_name, logs) html.footer()
def show_details(self, crash_info: CrashInfo, row) -> None: if not crash_info["details"]: return html.h3(_("Details"), class_="table") html.p( _("No detail renderer for crash of type '%s' available. Details structure is:" ) % crash_info["crash_type"]) html.pre(pprint.pformat(crash_info["details"]))
def _show_output_box(title: str, content: bytes) -> None: html.h3(title, class_="table") html.open_div(class_="log_output") html.write_html( HTML( escaping.escape_attribute( content.decode(errors="surrogateescape")).replace( "\n", "<br>").replace(" ", " "))) html.close_div()
def _display_multiple_days_audit_log(self, log): log = self._get_multiple_days_log_entries(log) if display_options.enabled(display_options.T): html.h3( _("Audit log for %s and %d days ago") % (render.date(self._get_start_date()), self._options["display"][1]) ) self._display_log(log)
def _display_daily_audit_log(self, log): log, times = self._get_next_daily_paged_log(log) self._display_page_controls(*times) if display_options.enabled(display_options.T): html.h3(_("Audit log for %s") % render.date(times[0])) self._display_log(log) self._display_page_controls(*times)
def _show_diagnose_output(self): if not request.var("_save"): html.show_message( _( "You can diagnose the connection to a specific host using this dialog. " "You can either test whether your current configuration is still working " "or investigate in which ways a host can be reached. Simply configure the " "connection options you like to try on the right side of the screen and " 'press the "Test" button. The results will be displayed here.' ) ) return if user_errors: html.show_user_errors() return # TODO: Insert any vs_host valuespec validation # These tests can be called with invalid valuespec settings... # TODO: Replace hard coded icon paths with dynamic ones to old or new theme for ident, title in ModeDiagHost.diag_host_tests(): html.h3(title) html.open_table(class_=["data", "test"]) html.open_tr(class_=["data", "odd0"]) html.open_td(class_="icons") html.open_div() html.icon("reload", id_="%s_img" % ident) html.open_a(href="") html.icon( "reload", title=_("Retry this test"), cssclass="retry", id_="%s_retry" % ident ) html.close_a() html.close_div() html.close_td() html.open_td() html.div("", class_="log", id="%s_log" % ident) html.close_td() html.close_tr() html.close_table() html.javascript( "cmk.host_diagnose.start_test(%s, %s, %s)" % ( json.dumps(ident), json.dumps(self._hostname), json.dumps(transactions.fresh_transid()), ) )
def render_werk_description(werk) -> HTML: with output_funnel.plugged(): html.open_p() in_list = False in_code = False for line in werk["body"]: if line.startswith("LI:"): if not in_list: html.open_ul() in_list = True html.li(line[3:]) else: if in_list: html.close_ul() in_list = False if line.startswith("H2:"): html.h3(line[3:]) elif line.startswith("C+:"): html.open_pre(class_="code") in_code = True elif line.startswith("F+:"): file_name = line[3:] if file_name: html.div(file_name, class_="filename") html.open_pre(class_="file") in_code = True elif line.startswith("C-:") or line.startswith("F-:"): html.close_pre() in_code = False elif line.startswith("OM:"): html.write_text("OMD[mysite]:~$ ") html.b(line[3:]) elif line.startswith("RP:"): html.write_text("root@myhost:~# ") html.b(line[3:]) elif not line.strip() and not in_code: html.p("") else: html.write_text(line + "\n") if in_list: html.close_ul() html.close_p() return HTML(output_funnel.drain())
def user_profile_async_replication_dialog(sites: Sequence[SiteId], back_url: str) -> None: html.p( _("In order to activate your changes available on all remote sites, your user profile needs " "to be replicated to the remote sites. This is done on this page now. Each site " "is being represented by a single image which is first shown gray and then fills " "to green during synchronisation.")) html.h3(_("Replication States")) html.open_div(id_="profile_repl") num_replsites = 0 for site_id in sites: site = active_config.sites[site_id] if "secret" not in site: status_txt = _("Not logged in.") start_sync = False icon = "repl_locked" else: status_txt = _("Waiting for replication to start") start_sync = True icon = "repl_pending" html.open_div(class_="site", id_="site-%s" % site_id) html.div("", title=status_txt, class_=["icon", "repl_status", icon]) if start_sync: changes_manager = ActivateChanges() changes_manager.load() estimated_duration = changes_manager.get_activation_time( site_id, ACTIVATION_TIME_PROFILE_SYNC, 2.0) html.javascript("cmk.profile_replication.start(%s, %d, %s);" % ( json.dumps(site_id), int(estimated_duration * 1000.0), json.dumps(_("Replication in progress")), )) num_replsites += 1 else: _add_profile_replication_change(site_id, status_txt) html.span(site.get("alias", site_id)) html.close_div() html.javascript("cmk.profile_replication.prepare(%d, %s);\n" % (num_replsites, json.dumps(back_url))) html.close_div()
def _show_popup(self, entry: PageMenuEntry) -> None: assert isinstance(entry.item, PageMenuPopup) if entry.name is None: raise ValueError('Missing "name" attribute on entry "%s"' % entry.title) classes = ["page_menu_popup"] classes += [c for c in entry.item.css_classes if c is not None] if isinstance(entry.item, PageMenuSidePopup): classes.append("side_popup") popup_id = "popup_%s" % entry.name html.open_div(id_=popup_id, class_=classes) html.open_div(class_="head") html.h3(entry.title) html.a( html.render_icon("close"), class_="close_popup", href="javascript:void(0)", onclick="cmk.page_menu.close_popup(this)", ) html.close_div() if ( isinstance(entry.item, PageMenuSidePopup) and entry.item.content and "side_popup_content" not in entry.item.content ): raise RuntimeError( 'Add a div container with the class "side_popup_content" to the popup content' ) html.open_div(class_="content") html.write_html(entry.item.content) html.close_div() html.close_div() if isinstance(entry.item, PageMenuSidePopup): html.final_javascript( "cmk.page_menu.side_popup_add_simplebar_scrollbar(%s);" % json.dumps(popup_id) )
def _show_crashed_section_details(self, info: CrashInfo) -> None: def format_bool(val): return { True: _("Yes"), False: _("No"), None: _("Unknown"), }[val] details = info["details"] html.h3(_("Details"), class_="table") html.open_table(class_="data") _crash_row(_("Section Name"), details["section_name"], odd=True) _crash_row(_("Inline-SNMP"), format_bool(details.get("inline_snmp")), odd=False, pre=True) html.close_table()
def render_werks_table(werk_table_options: Dict[str, Any]): translator = cmk.utils.werks.WerkTranslator() number_of_werks = 0 sorter, grouper = _SORT_AND_GROUP[werk_table_options["grouping"]] werklist = sorter(werk for werk in g_werks.values() if werk_matches_options(werk, werk_table_options) # ) groups = itertools.groupby(werklist, key=grouper) for group_title, werks in itertools.islice( groups, werk_table_options["group_limit"]): with table_element(title=group_title, limit=None, searchable=False, sortable=False, css="werks") as table: for werk in werks: number_of_werks += 1 render_werks_table_row(table, translator, werk) if not number_of_werks: html.h3(_("No matching Werks found."))
def render_mobile_list(rows, view, group_cells, cells, num_columns, show_checkboxes): if not is_mobile(request, response): html.show_error(_("This view can only be used in mobile mode.")) return # Force relative timestamp always. This saves space. painter_options = PainterOptions.get_instance() painter_options.set("ts_format", "rel") html.open_ul(class_="mobilelist", **{"data-role": "listview"}) # Paint data rows for row in rows: html.open_li() rendered_cells = [cell.render(row) for cell in cells] if rendered_cells: # First cell (assumedly state) is left rendered_class, rendered_content = rendered_cells[0] html.p(rendered_content, class_=["ui-li-aside", "ui-li-desc", rendered_class]) if len(rendered_cells) > 1: content = HTML(" · ").join([ rendered_cell[1] for rendered_cell in rendered_cells[1:num_columns + 1] ]) html.h3(content) for rendered_cell, cell in zip( rendered_cells[num_columns + 1:], cells[num_columns + 1:]): rendered_class, rendered_content = rendered_cell html.open_p(class_="ui-li-desc") cell.paint_as_header() html.write_text(": ") html.span(rendered_content, class_=rendered_class) html.close_p() html.close_li() html.close_ul() html.javascript('$("ul.mobilelist a").attr("data-ajax", "false");')
def _show_crashed_check_details(self, info: CrashInfo) -> None: def format_bool(val): return { True: _("Yes"), False: _("No"), None: _("Unknown"), }[val] details = info["details"] html.h3(_("Details"), class_="table") html.open_table(class_="data") _crash_row(_("Host"), details["host"], odd=False, legend=True) _crash_row(_("Is Cluster Host"), format_bool(details.get("is_cluster")), odd=True) _crash_row(_("Check Type"), details["check_type"], odd=False) _crash_row(_("Manual Check"), format_bool(details.get("manual_check")), odd=True, pre=True) _crash_row(_("Inline-SNMP"), format_bool(details.get("inline_snmp")), odd=True, pre=True) _crash_row(_("Check Item"), details.get("item", "This check has no item."), odd=False) _crash_row(_("Description"), details["description"], odd=True) if "params" in details: _crash_row(_("Parameters"), format_params(details["params"]), odd=False, pre=True) else: _crash_row(_("Parameters"), "This Check has no parameters", odd=False) html.close_table()
def _show_crash_report(self, info: CrashInfo) -> None: html.h3(_("Crash Report"), class_="table") html.open_table(class_=["data", "crash_report"]) _crash_row(_("Exception"), "%s (%s)" % (info["exc_type"], info["exc_value"]), odd=True, pre=True) _crash_row(_("Traceback"), self._format_traceback(info["exc_traceback"]), odd=False, pre=True) _crash_row( _("Local Variables"), format_local_vars(info["local_vars"]) if "local_vars" in info else "", odd=True, pre=True, ) _crash_row(_("Crash Type"), info["crash_type"], odd=False, legend=True) _crash_row(_("Time"), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(info["time"])), odd=True) _crash_row(_("Operating System"), info["os"], False) _crash_row(_("Checkmk Version"), info["version"], True) _crash_row(_("Edition"), info.get("edition", ""), False) _crash_row(_("Core"), info.get("core", ""), True) _crash_row(_("Python Version"), info.get("python_version", _("Unknown")), False) joined_paths = HTMLWriter.render_br().join( info.get("python_paths", [_("Unknown")])) _crash_row(_("Python Module Paths"), joined_paths, odd=False) html.close_table()
def _show_patterns(self): import cmk.gui.logwatch as logwatch collection = 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>.' % 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( Folder.current(), self._hostname, self._item, service_desc) else: # If no host/file given match all rules rule_matches = True with foldable_container( treename="rule", id_=str(abs_rulenr), isopen=True, title=HTML("<b>Rule #%d</b>" % (abs_rulenr + 1)), indent=False, ), table_element("pattern_editor_rule_%d" % abs_rulenr, sortable=False, css="logwatch") 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 matched = re.search(pattern, self._match_txt) if matched: # Prepare highlighted search txt match_start = matched.start() match_end = matched.end() disp_match_txt = ( escape_to_html(self._match_txt[:match_start]) + HTMLWriter.render_span( self._match_txt[match_start:match_end], class_="match") + escape_to_html(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 match_img = "nmatch" match_title = _("The rule conditions do not match.") table.row() table.cell(_("Match")) html.icon("rule%s" % match_img, match_title) cls = ([ "state%d" % logwatch.level_state(state), "fillbackground" ] if match_class == "match first" else []) table.cell(_("State"), HTMLWriter.render_span( logwatch.level_name(state)), css=cls) table.cell(_("Pattern"), HTMLWriter.render_tt(pattern)) table.cell(_("Comment"), comment) table.cell(_("Matched line"), disp_match_txt) table.row(fixed=True) table.cell(colspan=5) edit_url = folder_preserving_link([ ("mode", "edit_rule"), ("varname", "logwatch_rules"), ("rulenr", rulenr), ("item", mk_repr(self._item).decode()), ("rule_folder", folder.path()), ("rule_id", rule.id), ]) html.icon_button(edit_url, _("Edit this rule"), "edit")
def _rename_tags_after_confirmation( breadcrumb: Breadcrumb, operation: ABCOperation) -> Union[bool, str]: """Handle renaming and deletion of tags Find affected hosts, folders and rules. Remove or fix those rules according the users' wishes. Returns: True: Proceed, no "question" dialog shown False: "Question dialog" shown str: Action done after "question" dialog """ repair_mode = request.var("_repair") if repair_mode is not None: try: mode = TagCleanupMode(repair_mode) except ValueError: raise MKUserError("_repair", "Invalid mode") if mode == TagCleanupMode.ABORT: raise MKUserError("id_0", _("Aborting change.")) # make attribute unknown to system, important for save() operations if isinstance(operation, OperationRemoveTagGroup): undeclare_host_tag_attribute(operation.tag_group_id) affected_folders, affected_hosts, affected_rulesets = change_host_tags_in_folders( operation, mode, Folder.root_folder()) return _( "Modified folders: %d, modified hosts: %d, modified rulesets: %d" ) % ( len(affected_folders), len(affected_hosts), len(affected_rulesets), ) message = HTML() affected_folders, affected_hosts, affected_rulesets = change_host_tags_in_folders( operation, TagCleanupMode.CHECK, Folder.root_folder()) if affected_folders: with output_funnel.plugged(): html.write_text( _("Affected folders with an explicit reference to this tag " "group and that are affected by the change") + ":") _show_affected_folders(affected_folders) message += HTML(output_funnel.drain()) if affected_hosts: with output_funnel.plugged(): html.write_text( _("Hosts where this tag group is explicitely set " "and that are effected by the change") + ":") _show_affected_hosts(affected_hosts) message += HTML(output_funnel.drain()) if affected_rulesets: with output_funnel.plugged(): html.write_text( _("Rulesets that contain rules with references to the changed tags" ) + ":") _show_affected_rulesets(affected_rulesets) message += HTML(output_funnel.drain()) if message: wato_html_head(title=operation.confirm_title(), breadcrumb=breadcrumb) html.open_div(class_="really") html.h3(_("Your modifications affect some objects")) html.write_text(message) html.br() html.write_text( _("Setup can repair things for you. It can rename tags in folders, host and rules. " "Removed tag groups will be removed from hosts and folders, removed tags will be " "replaced with the default value for the tag group (for hosts and folders). What " "rules concern, you have to decide how to proceed.")) html.begin_form("confirm", method="POST") if affected_rulesets and _is_removing_tags(operation): html.br() html.b( _("Some tags that are used in rules have been removed by you. What " "shall we do with that rules?")) html.open_ul() html.radiobutton( "_repair", "remove", True, _("Just remove the affected tags from the rules.")) html.br() html.radiobutton( "_repair", "delete", False, _("Delete rules containing tags that have been removed, if tag is used in a positive sense. Just remove that tag if it's used negated." ), ) else: html.open_ul() html.radiobutton("_repair", "repair", True, _("Fix affected folders, hosts and rules.")) html.br() html.radiobutton("_repair", "abort", False, _("Abort your modifications.")) html.close_ul() html.button("_do_confirm", _("Proceed"), "") html.hidden_fields(add_action_vars=True) html.end_form() html.close_div() return False return True
def _write_table( self, rows: TableRows, num_rows_unlimited: int, actions_enabled: bool, actions_visible: bool, search_term: Optional[str], ) -> None: if not self.options["omit_update_header"]: row_info = _("1 row") if len( rows) == 1 else _("%d rows") % num_rows_unlimited html.javascript("cmk.utils.update_row_info(%s);" % json.dumps(row_info)) table_id = self.id num_cols = self._get_num_cols(rows) empty_columns = self._get_empty_columns(rows, num_cols) if self.options["omit_empty_columns"]: num_cols -= len([v for v in empty_columns if v]) html.open_table(class_=["data", "oddeven"] + self.css) # If we have no group headers then paint the headers now if self.rows and not isinstance(self.rows[0], GroupHeader): self._render_headers( actions_enabled, actions_visible, empty_columns, ) if actions_enabled and actions_visible: html.open_tr(class_=["data", "even0", "actions"]) html.open_td(colspan=num_cols) if not html.in_form(): html.begin_form("%s_actions" % table_id) if request.has_var("_%s_sort" % table_id): html.open_div(class_=["sort"]) html.button("_%s_reset_sorting" % table_id, _("Reset sorting")) html.close_div() if not html.in_form(): html.begin_form("%s_actions" % table_id) html.hidden_fields() html.end_form() html.close_tr() for nr, row in enumerate(rows): # Intermediate header if isinstance(row, GroupHeader): # Show the header only, if at least one (non-header) row follows if nr < len(rows) - 1 and not isinstance( rows[nr + 1], GroupHeader): html.open_tr(class_="groupheader") html.open_td(colspan=num_cols) html.h3(row.title) html.close_td() html.close_tr() self._render_headers(actions_enabled, actions_visible, empty_columns) continue oddeven_name = "even" if nr % 2 == 0 else "odd" class_ = ["data", "%s%d" % (oddeven_name, row.state)] if isinstance(row.css, list): class_.extend([c for c in row.css if c is not None]) elif row.css is not None: class_.append(row.css) html.open_tr(class_=class_, id_=row.id_, onmouseover=row.onmouseover, onmouseout=row.onmouseout) for col_index, cell in enumerate(row.cells): if self.options["omit_empty_columns"] and empty_columns[ col_index]: continue html.td(cell.content, class_=cell.css, colspan=cell.colspan) html.close_tr() if not rows and search_term: html.open_tr(class_=["data", "odd0", "no_match"]) html.td( _("Found no matching rows. Please try another search term."), colspan=num_cols) html.close_tr() html.close_table()
def _end(self) -> None: if not self.rows and self.options["omit_if_empty"]: return if self.options["output_format"] == "csv": self._write_csv(csv_separator=request.get_str_input_mandatory( "csv_separator", ";")) return container: ContextManager[bool] = nullcontext(False) if self.title: if self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.open_div(class_="foldable_wrapper") container = foldable_container( treename="table", id_=self.id, isopen=self.isopen, indent=False, title=HTMLWriter.render_h3(self.title, class_=["treeangle", "title"]), save_state=self.options["foldable"] == Foldable.FOLDABLE_SAVE_STATE, ) else: html.h3(self.title, class_="table") with container: if self.help: html.help(self.help) if not self.rows: html.div(self.empty_text, class_="info") return # Controls whether or not actions are available for a table rows, actions_visible, search_term = self._evaluate_user_opts() # Apply limit after search / sorting etc. num_rows_unlimited = len(rows) limit = self.limit if limit: # only use rows up to the limit plus the fixed rows limited_rows = [] for index in range(num_rows_unlimited): row = rows[index] if index < limit or isinstance(row, GroupHeader) or row.fixed: limited_rows.append(row) # Display corrected number of rows num_rows_unlimited -= len([ r for r in limited_rows if isinstance(row, GroupHeader) or r.fixed ]) rows = limited_rows # Render header if self.limit_hint is not None: num_rows_unlimited = self.limit_hint if limit and num_rows_unlimited > limit: html.show_message( _("This table is limited to show only %d of %d rows. " 'Click <a href="%s">here</a> to disable the limitation.') % (limit, num_rows_unlimited, makeuri(request, [("limit", "none")]))) self._write_table(rows, num_rows_unlimited, self._show_action_row(), actions_visible, search_term) if self.title and self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.close_div() return
def heading(text: str) -> None: html.h3(text)
def page(self): # Show outcome of host validation. Do not validate new hosts errors = None if self._mode == "edit": errors = (validate_all_hosts([self._host.name()]).get( self._host.name(), []) + self._host.validation_errors()) if errors: html.open_div(class_="info") html.open_table(class_="validationerror", boder="0", cellspacing="0", cellpadding="0") html.open_tr() html.open_td(class_="img") html.icon("validation_error") html.close_td() html.open_td() html.open_p() html.h3(_("Warning: This host has an invalid configuration!")) html.open_ul() for error in errors: html.li(error) html.close_ul() html.close_p() if html.form_submitted(): html.br() html.b(_("Your changes have been saved nevertheless.")) html.close_td() html.close_tr() html.close_table() html.close_div() lock_message = "" locked_hosts = Folder.current().locked_hosts() if locked_hosts: if locked_hosts is True: lock_message = _( "Host attributes locked (You cannot edit this host)") elif isinstance(locked_hosts, str): lock_message = locked_hosts if lock_message: html.div(lock_message, class_="info") html.begin_form("edit_host", method="POST") html.prevent_password_auto_completion() basic_attributes = [ # attribute name, valuepec, default value ("host", self._vs_host_name(), self._host.name()), ] if self._is_cluster(): basic_attributes += [ # attribute name, valuepec, default value ( "nodes", self._vs_cluster_nodes(), self._host.cluster_nodes() if self._host else [], ), ] configure_attributes( new=self._mode != "edit", hosts={self._host.name(): self._host} if self._mode != "new" else {}, for_what="host" if not self._is_cluster() else "cluster", parent=Folder.current(), basic_attributes=basic_attributes, ) if self._mode != "edit": html.set_focus("host") forms.end() html.hidden_fields() html.end_form()
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 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") % 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()