def _make_wato_page_state() -> PageState: changes_info = get_pending_changes_info() changelog_url = "wato.py?mode=changelog" span_id = "pending_changes" if changes_info: return PageState( text=html.render_span(changes_info, id_=span_id), icon_name="pending_changes", url=changelog_url, tooltip_text=(_tooltip_changes_info(changes_info) + "\n" + _("Click here to go to pending changes.")), ) return PageState(text=html.render_span(_("No pending changes"), id_=span_id), url=changelog_url, tooltip_text=_("Click here to see the activation status per site."))
def _render_tag_group(tg_id: Union[TagID, str], tag: Union[TagValue, str], object_type: str, with_link: bool, label_type: str, label_source: str) -> HTML: span = html.render_tag(html.render_div( html.render_span("%s:%s" % (tg_id, tag), class_=["tagify__tag-text"])), class_=["tagify--noAnim", label_source]) if not with_link: return span if label_type == "tag_group": type_filter_vars: HTTPVariables = [ ("%s_tag_0_grp" % object_type, tg_id), ("%s_tag_0_op" % object_type, "is"), ("%s_tag_0_val" % object_type, tag), ] elif label_type == "label": type_filter_vars = [ ("%s_label" % object_type, json.dumps([{ "value": "%s:%s" % (tg_id, tag) }])), ] else: raise NotImplementedError() url_vars: HTTPVariables = [ ("filled_in", "filter"), ("search", "Search"), ("view_name", "searchhost" if object_type == "host" else "searchsvc"), ] url = html.makeuri_contextless(url_vars + type_filter_vars, filename="view.py") return html.render_a(span, href=url)
def paint(self, value, hostname): value = convert_cgroups_from_tuple(value) texts: List[HTML] = [] self.load_data() if self._contactgroups is None: # conditional caused by horrible API raise Exception("invalid contact groups") items = self._contactgroups.items() for name, cgroup in sorted(items, key=lambda x: x[1]["alias"]): if name in value["groups"]: display_name = cgroup.get("alias", name) texts.append( html.render_a( display_name, href=makeuri_contextless( request, [("mode", "edit_contact_group"), ("edit", name)], filename="wato.py", ), )) result: HTML = HTML(", ").join(texts) if texts and value["use"]: result += html.render_span( html.render_b("*"), title= _("These contact groups are also used in the monitoring configuration." ), ) return "", result
def _render_tag_group(tg_id, tag, object_type, with_link, label_type, label_source): span = html.render_tag(html.render_div( html.render_span("%s:%s" % (tg_id, tag), class_=["tagify__tag-text"])), class_=["tagify--noAnim", label_source]) if not with_link: return span if label_type == "tag_group": type_filter_vars = [ ("%s_tag_0_grp" % object_type, tg_id), ("%s_tag_0_op" % object_type, "is"), ("%s_tag_0_val" % object_type, tag), ] elif label_type == "label": type_filter_vars = [ ("%s_label" % object_type, json.dumps([{ "value": "%s:%s" % (tg_id, tag) }]).decode("utf-8")), ] else: raise NotImplementedError() url = html.makeuri_contextless([ ("filled_in", "filter"), ("search", "Search"), ("view_name", "searchhost" if object_type == "host" else "searchsvc"), ] + type_filter_vars, filename="view.py") return html.render_a(span, href=url)
def _paint_aggr_state_short(state, assumed=False): if state is None: return "", "" name = short_service_state_name(state["state"], "") classes = "state svcstate state%s" % state["state"] if assumed: classes += " assumed" return classes, html.render_span(name, class_=["state_rounded_fill"])
def page(self): with table_element("roles") as table: users = userdb.load_users() for rid, role in sorted(self._roles.items(), key=lambda a: (a[1]["alias"], a[0])): table.row() # Actions table.cell(_("Actions"), css="buttons") edit_url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", rid)]) clone_url = make_action_link([("mode", "roles"), ("_clone", rid)]) delete_url = make_confirm_link( url=make_action_link([("mode", "roles"), ("_delete", rid)]), message=_("Do you really want to delete the role %s?") % rid, ) html.icon_button(edit_url, _("Properties"), "edit") html.icon_button(clone_url, _("Clone"), "clone") if not role.get("builtin"): html.icon_button(delete_url, _("Delete this role"), "delete") # ID table.cell(_("Name"), rid) # Alias table.cell(_("Alias"), role["alias"]) # Type table.cell( _("Type"), _("builtin") if role.get("builtin") else _("custom")) # Modifications table.cell( _("Modifications"), html.render_span( str(len(role["permissions"])), title= _("That many permissions do not use the factory defaults." ))) # Users table.cell( _("Users"), HTML(", ").join([ html.render_a( user.get("alias", user_id), watolib.folder_preserving_link([ ("mode", "edit_user"), ("edit", user_id) ])) for (user_id, user) in users.items() if rid in user["roles"] ]))
def _make_wato_page_state() -> PageState: changes_info = get_pending_changes_info() tooltip = get_pending_changes_tooltip() changelog_url = "wato.py?mode=changelog" span_id = "pending_changes" if changes_info: return PageState( text=html.render_span(changes_info, id_=span_id), icon_name="pending_changes", url=changelog_url, tooltip_text=tooltip, ) return PageState( text=html.render_span(_("No pending changes"), id_=span_id), icon_name="no_pending_changes", url=changelog_url, tooltip_text=tooltip, )
def _make_wato_page_state() -> PageState: changes_info = get_pending_changes_info() changelog_url = "wato.py?mode=changelog" span_id = "pending_changes" if changes_info: return PageState( text=html.render_span(changes_info, id_=span_id), icon_name="pending_changes", url=changelog_url, tooltip_text=ungettext(singular=_("Currently there is one change to activate"), plural=_("Currently there are %s to activate." % changes_info), n=int(re.findall(r"\d+", changes_info)[0])) + \ "\n" + _("Click here to go to pending changes."), ) return PageState( text=html.render_span(_("No pending changes"), id_=span_id), url=changelog_url, tooltip_text=_("Click here to see the activation status per site."))
def _release_switch(major: bool) -> PageState: patch_link = html.render_a(_("Patch release"), href=makeuri(request, [], remove_prefix=""), class_="active" if not major else None) major_link = html.render_a(_("Major release"), href=makeuri(request, [("major", 1)]), class_="active" if major else None) content = html.render_span(patch_link + major_link, id_="release_version_switch") return PageState(text=content)
def paint(self, value, hostname): value = convert_cgroups_from_tuple(value) texts = [] self.load_data() items = self._contactgroups.items() for name, cgroup in sorted(items, key=lambda x: x[1]['alias']): if name in value["groups"]: display_name = cgroup.get("alias", name) texts.append('<a href="wato.py?mode=edit_contact_group&edit=%s">%s</a>' % (name, display_name)) result = ", ".join(texts) if texts and value["use"]: result += html.render_span( html.render_b("*"), title=_("These contact groups are also used in the monitoring configuration.")) return "", result
def _render_headers(self, actions_enabled: bool, actions_visible: bool, empty_columns: List[bool]) -> None: if self.options["omit_headers"]: return table_id = self.id html.open_tr() first_col = True for nr, header in enumerate(self.headers): if self.options["omit_empty_columns"] and empty_columns[nr]: continue if header.help_txt: header_title: Union[int, HTML, str] = html.render_span( header.title, title=header.help_txt) else: header_title = header.title if not isinstance(header.css, list): css_class: CSSSpec = [header.css] else: css_class = header.css assert isinstance(css_class, list) css_class = [("header_%s" % c) for c in css_class if c is not None] if not self.options["sortable"] or not header.sortable: html.open_th(class_=css_class) else: css_class.insert(0, "sort") reverse = 0 sort = html.request.get_ascii_input('_%s_sort' % table_id) if sort: sort_col, sort_reverse = map(int, sort.split(',', 1)) if sort_col == nr: reverse = 1 if sort_reverse == 0 else 0 action_uri = html.makeactionuri([('_%s_sort' % table_id, '%d,%d' % (nr, reverse))]) html.open_th(class_=css_class, title=_("Sort by %s") % header.title, onclick="location.href='%s'" % action_uri) # Add the table action link if first_col: first_col = False if actions_enabled: if not header_title: header_title = " " # Fixes layout problem with white triangle if actions_visible: state = '0' help_txt = _('Hide table actions') img = 'table_actions_on' else: state = '1' help_txt = _('Display table actions') img = 'table_actions_off' html.open_div(class_=["toggle_actions"]) html.icon_button(html.makeuri([('_%s_actions' % table_id, state)]), help_txt, img, cssclass='toggle_actions') html.open_span() html.write(header_title) html.close_span() html.close_div() else: html.write(header_title) else: html.write(header_title) html.close_th() html.close_tr()
def _show_rows(self): rows = self._get_rows() if bool([r for r in rows if r.stats is None]): html.center(_("No data from any site")) return html.open_table(class_=["content_center", "tacticaloverview"], cellspacing="2", cellpadding="0", border="0") show_stales = self.parameters()["show_stale"] and config.user.may( "general.see_stales_in_tactical_overview") has_stale_objects = bool([r for r in rows if r.what != "events" and r.stats[-1]]) for row in rows: if row.what == "events": amount, problems, unhandled_problems = row.stats stales = 0 # no events open and disabled in local site: don't show events if amount == 0 and not config.mkeventd_enabled: continue else: amount, problems, unhandled_problems, stales = row.stats context_vars = get_context_url_variables(row.context) html.open_tr() html.th(row.title) html.th(_("Problems")) html.th(_("Unhandled")) if show_stales and has_stale_objects: html.th(_("Stale")) html.close_tr() td_class = 'col4' if has_stale_objects else 'col3' html.open_tr() url = html.makeuri_contextless(row.views.total + context_vars, filename="view.py") html.open_td(class_=["total", td_class]) html.a("%s" % amount, href=url, target="main") html.close_td() for value, ty in [(problems, "handled"), (unhandled_problems, "unhandled")]: url = html.makeuri_contextless(getattr(row.views, ty) + context_vars, filename="view.py") html.open_td(class_=[td_class, "states prob" if value != 0 else None]) link(str(value), url) html.close_td() if show_stales and has_stale_objects: if row.views.stale: url = html.makeuri_contextless(row.views.stale + context_vars, filename="view.py") html.open_td(class_=[td_class, "states prob" if stales != 0 else None]) link(str(stales), url) html.close_td() else: html.td(html.render_span("0")) html.close_tr() html.close_table()
def _render_headers(self, actions_enabled: bool, actions_visible: bool, empty_columns: List[bool]) -> None: if self.options["omit_headers"]: return table_id = self.id html.open_tr() first_col = True for nr, header in enumerate(self.headers): if self.options["omit_empty_columns"] and empty_columns[nr]: continue if header.help_txt: header_title: HTML = html.render_span(header.title, title=header.help_txt) else: header_title = header.title if not isinstance(header.css, list): css_class: "CSSSpec" = [header.css] else: css_class = header.css assert isinstance(css_class, list) css_class = [("header_%s" % c) for c in css_class if c is not None] if not self.options["sortable"] or not header.sortable: html.open_th(class_=css_class) else: css_class.insert(0, "sort") reverse = 0 sort = request.get_ascii_input("_%s_sort" % table_id) if sort: sort_col, sort_reverse = map(int, sort.split(",", 1)) if sort_col == nr: reverse = 1 if sort_reverse == 0 else 0 action_uri = makeactionuri(request, transactions, [("_%s_sort" % table_id, "%d,%d" % (nr, reverse))]) html.open_th( class_=css_class, title=_("Sort by %s") % header.title, onclick="location.href='%s'" % action_uri, ) # Add the table action link if first_col: first_col = False if actions_enabled: if not header_title: header_title = HTML( " " ) # Fixes layout problem with white triangle if actions_visible: state = "0" help_txt = _("Hide table actions") img = "table_actions_on" else: state = "1" help_txt = _("Display table actions") img = "table_actions_off" html.open_div(class_=["toggle_actions"]) html.icon_button( makeuri(request, [("_%s_actions" % table_id, state)]), help_txt, img, cssclass="toggle_actions", ) html.span(header_title) html.close_div() else: html.write_text(header_title) else: html.write_text(header_title) html.close_th() html.close_tr()
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()
def render_job_row(cls, job_id, job_status, odd, job_details_back_url=None): html.open_tr(css="data %s0" % odd) # Actions html.open_td(css="job_actions") if job_status.get("may_stop"): html.icon_button( makeactionuri(request, transactions, [(ActionHandler.stop_job_var, job_id)]), _("Stop this job"), "disable_test", ) if job_status.get("may_delete"): html.icon_button( makeactionuri(request, transactions, [(ActionHandler.delete_job_var, job_id)]), _("Delete this job"), "delete", ) html.close_td() # Job ID html.open_td(css="job_id") uri = makeuri_contextless( request, [ ("mode", "background_job_details"), ("back_url", job_details_back_url), ("job_id", job_id), ], filename="wato.py", ) html.a(job_id, href=uri) html.close_td() # Title html.td(job_status.get("title", _("Background Job")), css="job_title") # State html.td(html.render_span(job_status["state"]), css=cls.get_css_for_jobstate(job_status["state"])) # Started html.td(cmk.utils.render.date_and_time(job_status["started"]), css="job_started") # Owner html.td(job_status.get("user", _("Unknown user")), css="job_owner") # PID html.td(job_status["pid"] or "", css="job_pid") # Druation html.td(cmk.utils.render.timespan(job_status.get("duration", 0)), css="job_runtime") # Progress info loginfo = job_status.get("loginfo") if loginfo: if job_status.get( "state") == background_job.JobStatusStates.EXCEPTION: html.td(HTML("<br>".join(loginfo["JobException"])), css="job_last_progress") else: progress_text = "" if loginfo["JobProgressUpdate"]: progress_text += "%s" % loginfo["JobProgressUpdate"][-1] html.td(HTML(progress_text), css="job_last_progress") html.td(HTML("<br>".join(loginfo["JobResult"])), css="job_result") else: html.td("", css="job_last_progress") html.td("", css="job_result")
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 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]) + html.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: List[str] = [] if match_class == "match first": cls = ["state%d" % logwatch.level_state(state), "fillbackground"] table.cell(_("State"), html.render_span(logwatch.level_name(state)), css=cls) table.cell(_("Pattern"), html.render_tt(pattern)) table.cell(_("Comment"), 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), ("item", watolib.mk_repr(self._item).decode()), ("rule_folder", folder.path()), ("rule_id", rule.id), ] ) html.icon_button(edit_url, _("Edit this rule"), "edit")