Пример #1
0
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."))
Пример #2
0
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)
Пример #3
0
 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
Пример #4
0
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)
Пример #5
0
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"])
Пример #6
0
    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"]
                    ]))
Пример #7
0
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,
    )
Пример #8
0
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."))
Пример #9
0
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)
Пример #10
0
 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
Пример #11
0
    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 = "&nbsp;"  # 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()
Пример #12
0
    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()
Пример #13
0
    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(
                            "&nbsp;"
                        )  # 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()
Пример #14
0
    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()
Пример #15
0
    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")
Пример #16
0
    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")