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"), html.render_a(entry["title"], href=url), css="title") table.cell(_("Plugin Name"), html.render_tt(entry["name"]), css="name") table.cell(_("Agents"), ", ".join(map(translate, sorted(entry["agents"]))), css="agents")
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"] + html.normalize_css_spec(entry.item.css_classes) 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_log_list(): title = _("All problematic logfiles") breadcrumb = make_simple_page_breadcrumb( mega_menu_registry.menu_monitoring(), title) html.header(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( html.render_a( host_name, href=makeuri( request, [("site", site), ("host", host_name)], ), ), class_="table", ) list_logs(site, host_name, logs) html.footer()
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 page(self) -> None: html.h3(_("Upload Icon")) html.p( _("Allowed are single PNG image files with a maximum size of 80x80 px." )) html.begin_form('upload_form', method='POST') self._vs_upload().render_input('_upload_icon', None) html.hidden_fields() html.end_form() icons = sorted(self._load_custom_icons().items()) with table_element("icons", _("Custom Icons")) as table: for icon_name, category_name in icons: table.row() table.cell(_("Actions"), css="buttons") delete_url = make_action_link([("mode", "icons"), ("_delete", icon_name)]) html.icon_button(delete_url, _("Delete this Icon"), "delete") table.cell(_("Icon"), html.render_icon(icon_name), css="buttons") table.text_cell(_("Name"), icon_name) table.text_cell(_("Category"), IconSelector.category_alias(category_name))
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_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 config.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(_('No commands are possible in this view'))
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 = html.render_br().join(info.get("python_paths", [_("Unknown")])) _crash_row(_("Python Module Paths"), joined_paths, odd=False) html.close_table()
def render_availability_tables(availability_tables, what, avoptions): if not availability_tables: html.show_message(_("No matching hosts/services.")) return for group_title, availability_table in availability_tables: render_availability_table(group_title, availability_table, what, avoptions) # Legend for Availability levels av_levels = avoptions["av_levels"] if av_levels and "omit_av_levels" not in avoptions["labelling"]: warn, crit = av_levels html.open_div(class_="avlegend levels") html.h3(_("Availability levels")) html.div(_("OK"), class_="state state0") html.div("> %.3f%%" % warn, class_="level") html.div(_("WARN"), class_="state state1") html.div("> %.3f%%" % crit, class_="level") html.div(_("CRIT"), class_="state state2") html.div("< %.3f%%" % crit, class_="level") html.close_div() # Legend for timeline if "display_timeline_legend" in avoptions["labelling"] and avoptions[ "show_timeline"]: render_timeline_legend(what)
def _show_output_box(title, content): html.h3(title) html.open_div(class_="log_output") html.write( escaping.escape_attribute(content).replace("\n", "<br>").replace( ' ', ' ')) html.close_div()
def page(self): title = html.request.get_str_input_mandatory("title") host_css_class = html.request.get_str_input_mandatory("host_css_class") service_css_class = html.request.get_str_input_mandatory("service_css_class") num_services = html.request.get_integer_input_mandatory("num_services") num_problems = html.request.get_integer_input_mandatory("num_problems") with html.plugged(): html.h3(title) html.span( _("Host is %s" % (host_css_class if host_css_class != "downtime" else "in downtime"))) if host_css_class != "up": return {"host_tooltip": html.drain()} html.open_table() problem_services_str = _("problem services") if num_problems == 1: problem_services_str = _("service in %s state" % service_css_class) elif num_problems > 1: problem_services_str += _(" (worst state: %s)" % service_css_class) html.open_tr() html.td(str(num_services), class_="count") html.td(_("services") if num_services > 1 else _("service")) html.close_tr() html.open_tr() html.td(str(num_problems), class_="count") html.td(problem_services_str) html.close_tr() html.close_table() return {"host_tooltip": html.drain()}
def _show_output_box(title, content): html.h3(title, class_="table") html.open_div(class_="log_output") html.write_html( HTML(escaping.escape_attribute(content).replace("\n", "<br>").replace(" ", " ")) ) html.close_div()
def page(self) -> None: html.h3(_("Upload Icon")) html.p( _("Here you can add icons, for example to use them in bookmarks or " "in custom actions of views. Allowed are single PNG image files " "with a maximum size of 80x80 px. Custom actions have to be defined " "in the global settings and can be used in the custom icons rules " "of hosts and services.")) html.begin_form('upload_form', method='POST') self._vs_upload().render_input('_upload_icon', None) html.hidden_fields() html.end_form() icons = sorted(self._load_custom_icons().items()) with table_element("icons", _("Custom Icons")) as table: for icon_name, category_name in icons: table.row() table.cell(_("Actions"), css="buttons") delete_url = make_action_link([("mode", "icons"), ("_delete", icon_name)]) html.icon_button(delete_url, _("Delete this Icon"), "delete") table.cell(_("Icon"), html.render_icon(icon_name), css="buttons") table.text_cell(_("Name"), icon_name) table.text_cell(_("Category"), IconSelector.category_alias(category_name))
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 _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 show_details(self, crash_info, row): 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_status(self): job_status = self._get_job_status() html.h3(_("Job status")) if job_status["is_active"]: html.immediate_browser_redirect(0.8, html.makeuri([])) job = FetchAgentOutputBackgroundJob(self._request) gui_background_job.JobRenderer.show_job_details(job.get_job_id(), job_status)
def _show_job_info(self): if self._job_snapshot.is_active(): html.h3(_("Current status of synchronization process")) html.set_browser_reload(0.8) else: html.h3(_("Result of last synchronization process")) job_manager = gui_background_job.GUIBackgroundJobManager() job_manager.show_job_details_from_snapshot(job_snapshot=self._job_snapshot) html.br()
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_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 user_profile_async_replication_dialog(sites: List[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 = 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 = watolib.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 page(self): self._activation_msg() self._activation_form() html.h3(_("Activation status")) self._activation_status() if self.has_changes(): html.open_h3(class_="pending_changes_header") html.write_text(_("Pending changes")) html.div("", id_="row_info") html.close_h3() self._change_table()
def _show_diagnose_output(self): if not request.var("_try"): 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 _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_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 render_mobile_list(rows, view, group_cells, cells, num_columns, show_checkboxes): if not html.mobile: 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.open_p(class_=["ui-li-aside", "ui-li-desc", rendered_class]) html.write(rendered_content) html.close_p() 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.open_span(class_=rendered_class) html.write(rendered_content) html.close_span() html.close_p() html.close_li() html.close_ul() html.javascript('$("ul.mobilelist a").attr("data-ajax", "false");')
def _render_tooltip(cls, title: str, parts: List[Part], total_part: Part) -> str: with html.plugged(): html.h3(title) html.open_table() for part in parts: html.open_tr() html.td("", class_="color", style="background-color:%s" % part.color) html.td(str(part.count), class_="count") html.td(part.title, class_="title") html.close_tr() html.open_tr() html.td("", class_="color") html.td(str(total_part.count), class_="count") html.td(total_part.title, class_="title") html.close_tr() html.close_table() return html.drain()
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: List[Optional[str]] = ["page_menu_popup"] classes += entry.item.css_classes 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 user_profile_async_replication_dialog(sites): 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 = 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 = watolib.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\');' % (site_id, int(estimated_duration * 1000.0), _('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);\n' % num_replsites) html.close_div()