Пример #1
0
    def render(self, rows, view, group_cells, cells, num_columns,
               show_checkboxes):
        html.open_table(class_="data tiled")

        last_group = None
        group_open = False
        for row in rows:
            # Show group header
            if group_cells:
                this_group = group_value(row, group_cells)
                if this_group != last_group:

                    # paint group header
                    if group_open:
                        html.close_td()
                        html.close_tr()
                    html.open_tr()
                    html.open_td()
                    html.open_table(class_="groupheader")
                    html.open_tr(class_="groupheader")

                    painted = False
                    for cell in group_cells:
                        if painted:
                            html.td(', ')
                        painted = cell.paint(row)

                    html.close_tr()
                    html.close_table()

                    html.close_td()
                    html.close_tr()

                    html.open_tr()
                    html.open_td(class_="tiles")

                    group_open = True
                    last_group = this_group

            # background color of tile according to item state
            state = row.get("service_state", -1)
            if state == -1:
                hbc = row.get("host_has_been_checked", 1)
                if hbc:
                    state = row.get("host_state", 0)
                    sclass = "hhstate%d" % state
                else:
                    sclass = "hhstatep"
            else:
                hbc = row.get("service_has_been_checked", 1)
                if hbc:
                    sclass = "sstate%d" % state
                else:
                    sclass = "sstatep"

            if not group_open:
                html.open_tr()
                html.open_td(class_="tiles")
                group_open = True

            html.open_div(class_=["tile", sclass])
            html.open_table()

            # We need at least five cells
            if len(cells) < 5:
                cells = cells + ([EmptyCell(view)] * (5 - len(cells)))

            rendered = [cell.render(row) for cell in cells]

            html.open_tr()
            html.open_td(class_=["tl", rendered[1][0]])
            if show_checkboxes:
                render_checkbox(view, row, len(cells) - 1)
            html.write("%s" % rendered[1][1])
            html.close_td()
            html.open_td(class_=["tr", rendered[2][0]])
            html.write("%s" % rendered[2][1])
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.open_td(colspan=2, class_=["center", rendered[0][0]])
            html.write("%s" % rendered[0][1])
            html.close_td()
            html.close_tr()

            for css, cont in rendered[5:]:
                html.open_tr()
                html.open_td(colspan=2, class_=["cont", css])
                html.write("%s" % cont)
                html.close_td()
                html.close_tr()

            html.open_tr()
            html.open_td(class_=["bl", rendered[3][0]])
            html.write("%s" % rendered[3][1])
            html.close_td()
            html.open_td(class_=["br", rendered[4][0]])
            html.write("%s" % rendered[4][1])
            html.close_td()
            html.close_tr()

            html.close_table()
            html.close_div()

        if group_open:
            html.close_td()
            html.close_tr()

        html.close_table()
        init_rowselect(view)
Пример #2
0
    def _show_test_row(self, table, test_id, test_results_by_site, site_ids):
        table.row()

        table.cell(_("Actions"), css="buttons", sortable=False)
        html.icon_button(
            None,
            _("Toggle result details"),
            "toggle_details",
            onclick="cmk.wato.toggle_container('test_result_details_%s')" %
            test_id)

        worst_result = sorted(test_results_by_site["site_results"].values(),
                              key=lambda result: result.status)[0]

        # Disabling of test in total
        is_test_disabled = self._is_test_disabled(test_id)
        if is_test_disabled:
            html.icon_button(
                html.makeactionuri([
                    ("_do", "enable"),
                    ("_test_id", worst_result.test_id),
                ]),
                _("Reenable this test"),
                "enable_test",
            )
        else:
            html.icon_button(
                html.makeactionuri([
                    ("_do", "disable"),
                    ("_test_id", worst_result.test_id),
                ]),
                _("Disable this test"),
                "disable_test",
            )

        # assume all have the same test meta information (title, help, ...)
        table.cell(_("Title"),
                   css="title " + "stale" if is_test_disabled else "")
        html.write_text(test_results_by_site["test"]["title"])

        # Now loop all sites to display their results
        for site_id in site_ids:
            if is_test_disabled:
                table.cell(site_id, "")
                table.cell("", "")
                continue

            result = test_results_by_site["site_results"].get(site_id)
            if result is None:
                table.cell(site_id, css="state state-1")
                table.cell("", css="buttons")
                continue

            is_acknowledged = self._is_acknowledged(result)

            if is_acknowledged or result.status == -1:
                css = "state stale"
            else:
                css = "state state%d" % result.status

            table.cell(site_id, css=css)
            html.open_div(title=result.text)
            html.write_text(result.status_name())
            html.close_div()

            table.cell("", css="buttons")

            if result.status != 0:
                if is_acknowledged:
                    html.icon_button(
                        html.makeactionuri([
                            ("_do", "unack"),
                            ("_site_id", result.site_id),
                            ("_status_id", result.status),
                            ("_test_id", result.test_id),
                        ]),
                        _("Unacknowledge this test result for site %s") %
                        site_id,
                        "unacknowledge_test",
                    )
                else:
                    html.icon_button(
                        html.makeactionuri([
                            ("_do", "ack"),
                            ("_site_id", result.site_id),
                            ("_status_id", result.status),
                            ("_test_id", result.test_id),
                        ]),
                        _("Acknowledge this test result for site %s") %
                        site_id,
                        "acknowledge_test",
                    )
            else:
                html.write("")

        # Add toggleable notitication context
        table.row(class_="ac_test_details hidden",
                  id_="test_result_details_%s" % test_id)
        table.cell(colspan=2 + 2 * len(site_ids))

        html.write_text(test_results_by_site["test"]["help"])

        if not is_test_disabled:
            html.open_table()
            for site_id in site_ids:
                result = test_results_by_site["site_results"].get(site_id)
                if result is None:
                    continue

                html.open_tr()
                html.td(escaping.escape_attribute(site_id))
                html.td("%s: %s" % (result.status_name(), result.text))
                html.close_tr()
            html.close_table()

        # This dummy row is needed for not destroying the odd/even row highlighting
        table.row(class_="hidden")
Пример #3
0
    def _render_group(self, rows_with_ids, header, view, group_cells, cells,
                      num_columns, show_checkboxes):
        repeat_heading_every = 20  # in case column_headers is "repeat"

        html.open_table(class_="groupheader",
                        cellspacing=0,
                        cellpadding=0,
                        border=0)
        html.open_tr(class_="groupheader")
        painted = False
        for cell in group_cells:
            if painted:
                html.td(",&nbsp;")
            painted = cell.paint(rows_with_ids[0][1])
        html.close_tr()
        html.close_table()

        html.open_table(class_="data")
        odd = "odd"

        column_headers = view.get("column_headers")
        if column_headers != "off":
            self._show_header_line(cells, show_checkboxes)

        groups, rows_with_ids = calculate_view_grouping_of_services(
            rows_with_ids, row_group_cells=None)

        visible_row_number = 0
        group_hidden, num_grouped_rows = None, 0
        for index, row in rows_with_ids:
            if view.get("column_headers") == "repeat":
                if visible_row_number > 0 and visible_row_number % repeat_heading_every == 0:
                    self._show_header_line(cells, show_checkboxes)
            visible_row_number += 1

            odd = "even" if odd == "odd" else "odd"

            # state = row.get("service_state", row.get("aggr_state"))
            state = utils.saveint(row.get("service_state"))
            if state is None:
                state = utils.saveint(row.get("host_state", 0))
                if state > 0:
                    state += 1  # 1 is critical for hosts

            num_cells = len(cells)

            if index in groups:
                group_spec, num_grouped_rows = groups[index]
                group_hidden = grouped_row_title(index, group_spec,
                                                 num_grouped_rows, odd,
                                                 num_cells)
                odd = "even" if odd == "odd" else "odd"

            css_classes = []

            if is_stale(row):
                css_classes.append("stale")

            hide = ""
            if num_grouped_rows > 0:
                num_grouped_rows -= 1
                if group_hidden:
                    hide = "display:none"

            if group_hidden is not None and num_grouped_rows == 0:
                # last row in group
                css_classes.append("group_end")
                group_hidden = None

            css_classes.append("%s%d" % (odd, state))

            html.open_tr(class_=["data"] + css_classes, style=hide)

            if show_checkboxes:
                render_checkbox_td(view, row, num_cells)

            for cell in cells:
                cell.paint(row)

            html.close_tr()

        html.close_table()
        init_rowselect(view)
Пример #4
0
    def show(self):
        pie_id = "dashlet_%d" % self._dashlet_id
        pie_diameter = 130
        pie_left_aspect = 0.5
        pie_right_aspect = 0.8
        table = self._table()

        filter_headers, only_sites = visuals.get_filter_headers(
            table=self._livestatus_table(),
            infos=self.infos(),
            context=self.context)

        query = "GET %s\n" % self._livestatus_table()
        for entry in table:
            query += entry[3]
        query += self._filter() + filter_headers

        if only_sites:
            try:
                sites.live().set_only_sites(only_sites)
                result: List[int] = sites.live().query_row(query)
            finally:
                sites.live().set_only_sites()
        else:
            try:
                result = sites.live().query_summed_stats(query)
            except MKLivestatusNotFoundError:
                result = []

        pies = list(zip(table, result))
        total = sum([x[1] for x in pies])

        html.open_div(class_="stats")
        html.canvas('',
                    class_="pie",
                    id_="%s_stats" % pie_id,
                    width="%d" % pie_diameter,
                    height="%d" % pie_diameter,
                    style="float: left")
        html.img(html.theme_url("images/globe.png"), class_="globe")

        html.open_table(class_=["hoststats"] +
                        (["narrow"] if len(pies) > 0 else []),
                        style="float:left")

        table_entries: List[Tuple] = []
        table_entries += pies
        while len(table_entries) < 6:
            table_entries = table_entries + [(
                ("", None, [], ""), HTML("&nbsp;"))]
        table_entries.append(((_("Total"), "", [], ""), total))

        for (name, color, table_url_vars, query), count in table_entries:
            url_vars = [
                ("view_name", self._view_name()),
                ("filled_in", "filter"),
                ("search", "1"),
            ] + table_url_vars + self._dashlet_context_vars()
            url = makeuri_contextless(request, url_vars, filename="view.py")

            html.open_tr()
            html.th(html.render_a(name, href=url))
            html.td('',
                    class_="color",
                    style="background-color: %s" % color if color else '')
            html.td(html.render_a(count, href=url))
            html.close_tr()

        html.close_table()

        pie_parts = []
        if total > 0:
            # Count number of non-empty classes
            num_nonzero = 0
            for _info, value in pies:
                if value > 0:
                    num_nonzero += 1

            # Each non-zero class gets at least a view pixels of visible thickness.
            # We reserve that space right now. All computations are done in percent
            # of the radius.
            separator = 0.02  # 3% of radius
            remaining_separatorspace = num_nonzero * separator  # space for separators
            remaining_radius = 1 - remaining_separatorspace  # remaining space
            remaining_part = 1.0  # keep track of remaining part, 1.0 = 100%

            # Loop over classes, begin with most outer sphere. Inner spheres show
            # worse states and appear larger to the user (which is the reason we
            # are doing all this stuff in the first place)
            for (name, color, _unused, _q), value in pies[::1]:
                if value > 0 and remaining_part > 0:  # skip empty classes

                    # compute radius of this sphere *including all inner spheres!* The first
                    # sphere always gets a radius of 1.0, of course.
                    radius = remaining_separatorspace + remaining_radius * (
                        remaining_part**(1 / 3.0))
                    pie_parts.append('chart_pie("%s", %f, %f, %r, true);' %
                                     (pie_id, pie_right_aspect, radius, color))
                    pie_parts.append('chart_pie("%s", %f, %f, %r, false);' %
                                     (pie_id, pie_left_aspect, radius, color))

                    # compute relative part of this class
                    part = float(value) / total  # ranges from 0 to 1
                    remaining_part -= part
                    remaining_separatorspace -= separator

        html.close_div()

        html.javascript(
            """
function chart_pie(pie_id, x_scale, radius, color, right_side) {
    var context = document.getElementById(pie_id + "_stats").getContext('2d');
    if (!context)
        return;
    var pie_x = %(x)f;
    var pie_y = %(y)f;
    var pie_d = %(d)f;
    context.fillStyle = color;
    context.save();
    context.translate(pie_x, pie_y);
    context.scale(x_scale, 1);
    context.beginPath();
    if(right_side)
        context.arc(0, 0, (pie_d / 2) * radius, 1.5 * Math.PI, 0.5 * Math.PI, false);
    else
        context.arc(0, 0, (pie_d / 2) * radius, 0.5 * Math.PI, 1.5 * Math.PI, false);
    context.closePath();
    context.fill();
    context.restore();
    context = null;
}


if (cmk.dashboard.has_canvas_support()) {
    %(p)s
}
""" % {
                "x": int(pie_diameter / 2.0),
                "y": int(pie_diameter / 2.0),
                "d": pie_diameter,
                'p': '\n'.join(pie_parts)
            })
Пример #5
0
 def werk_table_row(caption, content, css=None):
     html.open_tr()
     html.th(caption)
     html.td(content, class_=css)
     html.close_tr()
Пример #6
0
    def show_job_details(cls, job_id, job_status):
        """Renders the complete job details in a single table with left headers"""
        html.open_table(class_=["data", "headerleft", "job_details"])

        # Static info
        for left, right in [
            (_("ID"), job_id),
            (_("Title"), job_status.get("title", "")),
            (_("Started"),
             cmk.utils.render.date_and_time(job_status["started"])),
            (_("Owner"), job_status.get("user", "")),
        ]:
            html.open_tr()
            html.th(left)
            html.td(right)
            html.close_tr()

        # Actions
        html.open_tr()
        html.th(_("Actions"))
        html.open_td()
        if job_status.get("may_stop"):
            html.icon_button(
                html.makeactionuri([(ActionHandler.stop_job_var, job_id)]),
                _("Stop this job"),
                "disable_test",
            )
        if job_status.get("may_delete"):
            html.icon_button(
                html.makeactionuri([(ActionHandler.delete_job_var, job_id)]),
                _("Delete this job"),
                "delete",
            )
        html.close_td()
        html.close_tr()

        # Job state
        html.open_tr()
        html.th(_("State"))
        html.td(job_status["state"],
                css=cls.get_css_for_jobstate(job_status["state"]))
        html.close_tr()

        if job_status["state"] == background_job.JobStatusStates.EXCEPTION:
            html.open_tr()
            html.th(_("Acknowledged by"))
            html.td(job_status.get("acknowledged_by", ""))
            html.close_tr()

        # Dynamic data
        loginfo = job_status.get("loginfo")
        runtime_info = six.ensure_text(
            cmk.utils.render.timespan(job_status.get("duration", 0)))
        if job_status["state"] == background_job.JobStatusStates.RUNNING \
            and job_status.get("estimated_duration") is not None:
            runtime_info += u" (%s: %s)" % (
                _("estimated duration"),
                six.ensure_text(
                    cmk.utils.render.timespan(
                        job_status["estimated_duration"])))
        for left, right in [
            (_("Runtime"), runtime_info),
            (_("PID"), job_status["pid"] or ""),
            (_("Result"), "<br>".join(loginfo["JobResult"])),
        ]:
            if right is None:
                continue
            html.open_tr()
            html.th(left)
            html.td(HTML(right))
            html.close_tr()

        # Exceptions
        exceptions = loginfo["JobException"]
        if exceptions:
            html.open_tr()
            html.th(_("Exceptions"))
            html.open_td()
            if exceptions and "logfile_path" in job_status:
                exceptions.append(
                    _("More information can be found in %s") %
                    job_status["logfile_path"])
            html.open_div(class_="log_output", id_="exception_log")
            html.pre("\n".join(exceptions))
            html.close_div()
            html.close_td()
            html.close_tr()

        # Progress Update
        html.open_tr()
        html.th(_("Progress Info"))
        html.open_td()
        html.open_div(class_="log_output",
                      style="height: 400px;",
                      id_="progress_log")
        html.pre(HTML("\n").join(loginfo["JobProgressUpdate"]))
        html.close_div()
        html.close_td()
        html.close_tr()

        html.close_table()
        html.javascript(
            "var log = document.getElementById('progress_log'); log.scrollTop = log.scrollHeight;"
        )
Пример #7
0
    def show(self):
        if not watolib.is_wato_slave_site():
            if not config.wato_enabled:
                html.write_text(_("WATO is disabled."))
                return False

        user_folders = compute_foldertree()

        #
        # Render link target selection
        #
        selected_topic, selected_target = config.user.load_file("foldertree",
                                                                (_('Hosts'), 'allhosts'))

        # Apply some view specific filters
        views_to_show = [(name, view)
                         for name, view in views.get_permitted_views().items()
                         if (not config.visible_views or name in config.visible_views) and
                         (not config.hidden_views or name not in config.hidden_views)]

        visuals_to_show = [("views", e) for e in views_to_show]
        visuals_to_show += [("dashboards", e) for e in dashboard.get_permitted_dashboards().items()]

        topics = make_topic_menu(visuals_to_show)
        topic_choices: Choices = [(topic.title, topic.title) for topic in topics]

        html.open_table()
        html.open_tr()
        html.td(_('Topic:'), class_="label")
        html.open_td()
        html.dropdown("topic",
                      topic_choices,
                      deflt=selected_topic,
                      onchange='cmk.sidebar.wato_tree_topic_changed(this)')
        html.close_td()
        html.close_tr()

        html.open_tr()
        html.td(_("View:"), class_="label")
        html.open_td()

        for topic in topics:
            targets: Choices = []
            for item in topic.items:
                if item.url.startswith("dashboards.py"):
                    name = 'dashboard|' + item.name
                else:
                    name = item.name
                targets.append((name, item.title))

            if topic.title != selected_topic:
                default = ''
                style: Optional[str] = 'display:none'
            else:
                default = selected_target
                style = None
            html.dropdown("target_%s" % topic.title,
                          targets,
                          deflt=default,
                          onchange='cmk.sidebar.wato_tree_target_changed(this)',
                          style=style)

        html.close_td()
        html.close_tr()
        html.close_table()

        # Now render the whole tree
        if user_folders:
            render_tree_folder("wato-hosts",
                               list(user_folders.values())[0], 'cmk.sidebar.wato_tree_click')
Пример #8
0
    def page(self):
        # Let exceptions from loading notification scripts happen now
        watolib.load_notification_scripts()

        html.begin_form("user", method="POST")
        html.prevent_password_auto_completion()

        forms.header(_("Identity"))

        # ID
        forms.section(_("Username"), simple=not self._is_new_user)
        if self._is_new_user:
            vs_user_id = UserID(allow_empty=False)

        else:
            vs_user_id = FixedValue(self._user_id)
        vs_user_id.render_input("user_id", self._user_id)

        def lockable_input(name, dflt):
            if not self._is_locked(name):
                html.text_input(name, self._user.get(name, dflt), size=50)
            else:
                html.write_text(self._user.get(name, dflt))
                html.hidden_field(name, self._user.get(name, dflt))

        # Full name
        forms.section(_("Full name"))
        lockable_input('alias', self._user_id)
        html.help(_("Full name or alias of the user"))

        # Email address
        forms.section(_("Email address"))
        email = self._user.get("email", "")
        if not self._is_locked("email"):
            EmailAddress().render_input("email", email)
        else:
            html.write_text(email)
            html.hidden_field("email", email)

        html.help(
            _("The email address is optional and is needed "
              "if the user is a monitoring contact and receives notifications "
              "via Email."))

        forms.section(_("Pager address"))
        lockable_input('pager', '')
        html.help(_("The pager address is optional "))

        if cmk_version.is_managed_edition():
            forms.section(self._vs_customer.title())
            self._vs_customer.render_input("customer",
                                           managed.get_customer_id(self._user))

            html.help(self._vs_customer.help())

        vs_sites = self._vs_sites()
        forms.section(vs_sites.title())
        authorized_sites = self._user.get("authorized_sites",
                                          vs_sites.default_value())
        if not self._is_locked("authorized_sites"):
            vs_sites.render_input("authorized_sites", authorized_sites)
        else:
            html.write_html(vs_sites.value_to_text(authorized_sites))
        html.help(vs_sites.help())

        self._show_custom_user_attributes('ident')

        forms.header(_("Security"))
        forms.section(_("Authentication"))

        is_automation = self._user.get("automation_secret", None) is not None
        html.radiobutton("authmethod", "password", not is_automation,
                         _("Normal user login with password"))
        html.open_ul()
        html.open_table()
        html.open_tr()
        html.td(_("password:"******"_password_" + self._pw_suffix(),
                                autocomplete="new-password")
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.td(_("repeat:"))
            html.open_td()
            html.password_input("_password2_" + self._pw_suffix(),
                                autocomplete="new-password")
            html.write_text(" (%s)" % _("optional"))
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.td("%s:" % _("Enforce change"))
            html.open_td()
            # Only make password enforcement selection possible when user is allowed to change the PW
            uid = None if self._user_id is None else UserId(self._user_id)
            if (self._is_new_user
                    or (config.user_may(uid, 'general.edit_profile')
                        and config.user_may(uid, 'general.change_password'))):
                html.checkbox(
                    "enforce_pw_change",
                    self._user.get("enforce_pw_change", False),
                    label=_("Change password at next login or access"))
            else:
                html.write_text(
                    _("Not permitted to change the password. Change can not be enforced."
                      ))
        else:
            html.i(
                _('The password can not be changed (It is locked by the user connector).'
                  ))
            html.hidden_field('_password', '')
            html.hidden_field('_password2', '')

        html.close_td()
        html.close_tr()
        html.close_table()
        html.close_ul()

        html.radiobutton("authmethod", "secret", is_automation,
                         _("Automation secret for machine accounts"))

        html.open_ul()
        html.text_input("_auth_secret",
                        self._user.get("automation_secret", ""),
                        size=30,
                        id_="automation_secret")
        html.write_text(" ")
        html.open_b(style=["position: relative", "top: 4px;"])
        html.write(" &nbsp;")
        html.icon_button(
            "javascript:cmk.wato.randomize_secret('automation_secret', 20);",
            _("Create random secret"), "random")
        html.close_b()
        html.close_ul()

        html.help(
            _("If you want the user to be able to login "
              "then specify a password here. Users without a login make sense "
              "if they are monitoring contacts that are just used for "
              "notifications. The repetition of the password is optional. "
              "<br>For accounts used by automation processes (such as fetching "
              "data from views for further procession), set the method to "
              "<u>secret</u>. The secret will be stored in a local file. Processes "
              "with read access to that file will be able to use Multisite as "
              "a webservice without any further configuration."))

        # Locking
        forms.section(_("Disable password"), simple=True)
        if not self._is_locked('locked'):
            html.checkbox("locked",
                          self._user.get("locked", False),
                          label=_("disable the login to this account"))
        else:
            html.write_text(
                _('Login disabled') if self._user.
                get("locked", False) else _('Login possible'))
            html.hidden_field('locked',
                              '1' if self._user.get("locked", False) else '')
        html.help(
            _("Disabling the password will prevent a user from logging in while "
              "retaining the original password. Notifications are not affected "
              "by this setting."))

        forms.section(_("Idle timeout"))
        idle_timeout = self._user.get("idle_timeout")
        if not self._is_locked("idle_timeout"):
            watolib.get_vs_user_idle_timeout().render_input(
                "idle_timeout", idle_timeout)
        else:
            html.write_text(idle_timeout)
            html.hidden_field("idle_timeout", idle_timeout)

        # Roles
        forms.section(_("Roles"))
        is_member_of_at_least_one = False
        for role_id, role in sorted(self._roles.items(),
                                    key=lambda x: (x[1]["alias"], x[0])):
            if not self._is_locked("roles"):
                html.checkbox("role_" + role_id, role_id
                              in self._user.get("roles", []))
                url = watolib.folder_preserving_link([("mode", "edit_role"),
                                                      ("edit", role_id)])
                html.a(role["alias"], href=url)
                html.br()
            else:
                is_member = role_id in self._user.get("roles", [])
                if is_member:
                    is_member_of_at_least_one = True
                    url = watolib.folder_preserving_link([("mode",
                                                           "edit_role"),
                                                          ("edit", role_id)])
                    html.a(role["alias"], href=url)
                    html.br()

                html.hidden_field("role_" + role_id, '1' if is_member else '')
        if self._is_locked('roles') and not is_member_of_at_least_one:
            html.i(_('No roles assigned.'))
        self._show_custom_user_attributes('security')

        # Contact groups
        forms.header(_("Contact Groups"), isopen=False)
        forms.section()
        groups_page_url = watolib.folder_preserving_link([("mode",
                                                           "contact_groups")])
        group_assign_url = watolib.folder_preserving_link([
            ("mode", "rulesets"), ("group", "grouping")
        ])
        if not self._contact_groups:
            html.write(
                _("Please first create some <a href='%s'>contact groups</a>") %
                groups_page_url)
        else:
            entries = sorted([(group['alias'] or c, c)
                              for c, group in self._contact_groups.items()])
            is_member_of_at_least_one = False
            for alias, gid in entries:
                is_member = gid in self._user.get("contactgroups", [])

                if not self._is_locked('contactgroups'):
                    html.checkbox("cg_" + gid, gid
                                  in self._user.get("contactgroups", []))
                else:
                    if is_member:
                        is_member_of_at_least_one = True
                    html.hidden_field("cg_" + gid, '1' if is_member else '')

                if not self._is_locked('contactgroups') or is_member:
                    url = watolib.folder_preserving_link([
                        ("mode", "edit_contact_group"), ("edit", gid)
                    ])
                    html.a(alias, href=url)
                    html.br()

            if self._is_locked(
                    'contactgroups') and not is_member_of_at_least_one:
                html.i(_('No contact groups assigned.'))

        html.help(
            _("Contact groups are used to assign monitoring "
              "objects to users. If you haven't defined any contact groups yet, "
              "then first <a href='%s'>do so</a>. Hosts and services can be "
              "assigned to contact groups using <a href='%s'>rules</a>.<br><br>"
              "If you do not put the user into any contact group "
              "then no monitoring contact will be created for the user.") %
            (groups_page_url, group_assign_url))

        forms.header(_("Notifications"), isopen=False)
        if not self._rbn_enabled():
            forms.section(_("Enabling"), simple=True)
            html.checkbox("notifications_enabled",
                          self._user.get("notifications_enabled", False),
                          label=_("enable notifications"))
            html.help(
                _("Notifications are sent out "
                  "when the status of a host or service changes."))

            # Notification period
            forms.section(_("Notification time period"))
            user_np = self._user.get("notification_period")
            if not isinstance(user_np, str):
                raise Exception("invalid notification period %r" % (user_np, ))
            choices: Choices = [(id_, "%s" % (tp["alias"]))
                                for (id_, tp) in self._timeperiods.items()]
            html.dropdown("notification_period",
                          choices,
                          deflt=user_np,
                          ordered=True)
            html.help(
                _("Only during this time period the "
                  "user will get notifications about host or service alerts."))

            # Notification options
            notification_option_names = {  # defined here: _() must be executed always!
                "host": {
                    "d": _("Host goes down"),
                    "u": _("Host gets unreachble"),
                    "r": _("Host goes up again"),
                },
                "service": {
                    "w": _("Service goes into warning state"),
                    "u": _("Service goes into unknown state"),
                    "c": _("Service goes into critical state"),
                    "r": _("Service recovers to OK"),
                },
                "both": {
                    "f": _("Start or end of flapping state"),
                    "s": _("Start or end of a scheduled downtime"),
                }
            }

            forms.section(_("Notification Options"))
            for title, what, opts in [(_("Host events"), "host", "durfs"),
                                      (_("Service events"), "service",
                                       "wucrfs")]:
                html.write_text("%s:" % title)
                html.open_ul()

                user_opts = self._user.get(what + "_notification_options",
                                           opts)
                for opt in opts:
                    opt_name = notification_option_names[what].get(
                        opt, notification_option_names["both"].get(opt))
                    html.checkbox(what + "_" + opt,
                                  opt in user_opts,
                                  label=opt_name)
                    html.br()
                html.close_ul()

            html.help(
                _("Here you specify which types of alerts "
                  "will be notified to this contact. Note: these settings will only be saved "
                  "and used if the user is member of a contact group."))

            forms.section(_("Notification Method"))
            watolib.get_vs_flexible_notifications().render_input(
                "notification_method", self._user.get("notification_method"))

        else:
            forms.section(_("Fallback notifications"), simple=True)

            html.checkbox("fallback_contact",
                          self._user.get("fallback_contact", False),
                          label=_("Receive fallback notifications"))

            html.help(
                _("In case none of your notification rules handles a certain event a notification "
                  "will be sent to this contact. This makes sure that in that case at least <i>someone</i> "
                  "gets notified. Furthermore this contact will be used for notifications to any host or service "
                  "that is not known to the monitoring. This can happen when you forward notifications "
                  "from the Event Console.<br><br>Notification fallback can also configured in the global "
                  "setting <a href=\"wato.py?mode=edit_configvar&varname=notification_fallback_email\">"
                  "Fallback email address for notifications</a>."))

        self._show_custom_user_attributes('notify')

        forms.header(_("Personal Settings"), isopen=False)
        select_language(self._user)
        self._show_custom_user_attributes('personal')

        # Later we could add custom macros here, which then could be used
        # for notifications. On the other hand, if we implement some check_mk
        # --notify, we could directly access the data in the account with the need
        # to store values in the monitoring core. We'll see what future brings.
        forms.end()
        if self._is_new_user:
            html.set_focus("user_id")
        else:
            html.set_focus("alias")
        html.hidden_fields()
        html.end_form()
Пример #9
0
    def show(self):
        # pie_id, what, table, filter, dashlet):
        pie_id = "dashlet_%d" % self._dashlet_id
        pie_diameter = 130
        pie_left_aspect = 0.5
        pie_right_aspect = 0.8
        what = self._livestatus_table()
        table = self._table()
        filter_ = self._filter()

        if what == 'hosts':
            info = 'host'
            infos = [info]
        else:
            info = 'service'
            infos = ['host', 'service']
        use_filters = visuals.filters_of_visual(self._dashlet_spec, infos)
        for filt in use_filters:
            if filt.available() and not isinstance(filt, FilterCRESite):
                filter_ += filt.filter(info)

        query = "GET %s\n" % what
        for entry in table:
            query += entry[3]
        query += filter_

        site = self._dashlet_spec['context'].get('siteopt', {}).get('site')
        if site:
            sites.live().set_only_sites([site])
            result = sites.live().query_row(query)
            sites.live().set_only_sites()
        else:
            try:
                result = sites.live().query_summed_stats(query)
            except MKLivestatusNotFoundError:
                result = []

        pies = zip(table, result)
        total = sum([x[1] for x in pies])

        html.open_div(class_="stats")
        html.canvas('',
                    class_="pie",
                    id_="%s_stats" % pie_id,
                    width=pie_diameter,
                    height=pie_diameter,
                    style="float: left")
        html.img(html.theme_url("images/globe.png"), class_="globe")

        html.open_table(class_=["hoststats"] +
                        (["narrow"] if len(pies) > 0 else []),
                        style="float:left")

        table_entries = pies
        while len(table_entries) < 6:
            table_entries = table_entries + [(
                ("", None, "", ""), HTML("&nbsp;"))]
        table_entries.append(((_("Total"), "", "all%s" % what, ""), total))

        for (name, color, viewurl, query), count in table_entries:
            url = "view.py?view_name=" + viewurl + "&filled_in=filter&search=1"
            for filter_name, url_params in self._dashlet_spec['context'].items(
            ):
                if filter_name == "wato_folder" and html.request.has_var(
                        "wato_folder"):
                    url += "&wato_folder=" + html.request.var("wato_folder")

                elif filter_name == "svcstate":
                    # The svcstate filter URL vars are controlled by dashlet
                    continue

                else:
                    url += '&' + html.urlencode_vars(url_params.items())

            html.open_tr()
            html.th(html.render_a(name, href=url))
            html.td('',
                    class_="color",
                    style="background-color: %s" % color if color else '')
            html.td(html.render_a(count, href=url))
            html.close_tr()

        html.close_table()

        pie_parts = []
        if total > 0:
            # Count number of non-empty classes
            num_nonzero = 0
            for info, value in pies:
                if value > 0:
                    num_nonzero += 1

            # Each non-zero class gets at least a view pixels of visible thickness.
            # We reserve that space right now. All computations are done in percent
            # of the radius.
            separator = 0.02  # 3% of radius
            remaining_separatorspace = num_nonzero * separator  # space for separators
            remaining_radius = 1 - remaining_separatorspace  # remaining space
            remaining_part = 1.0  # keep track of remaining part, 1.0 = 100%

            # Loop over classes, begin with most outer sphere. Inner spheres show
            # worse states and appear larger to the user (which is the reason we
            # are doing all this stuff in the first place)
            for (name, color, viewurl, _q), value in pies[::1]:
                if value > 0 and remaining_part > 0:  # skip empty classes

                    # compute radius of this sphere *including all inner spheres!* The first
                    # sphere always gets a radius of 1.0, of course.
                    radius = remaining_separatorspace + remaining_radius * (
                        remaining_part**(1 / 3.0))
                    pie_parts.append('chart_pie("%s", %f, %f, %r, true);' %
                                     (pie_id, pie_right_aspect, radius, color))
                    pie_parts.append('chart_pie("%s", %f, %f, %r, false);' %
                                     (pie_id, pie_left_aspect, radius, color))

                    # compute relative part of this class
                    part = float(value) / total  # ranges from 0 to 1
                    remaining_part -= part
                    remaining_separatorspace -= separator

        html.close_div()

        html.javascript(
            """
function chart_pie(pie_id, x_scale, radius, color, right_side) {
    var context = document.getElementById(pie_id + "_stats").getContext('2d');
    if (!context)
        return;
    var pie_x = %(x)f;
    var pie_y = %(y)f;
    var pie_d = %(d)f;
    context.fillStyle = color;
    context.save();
    context.translate(pie_x, pie_y);
    context.scale(x_scale, 1);
    context.beginPath();
    if(right_side)
        context.arc(0, 0, (pie_d / 2) * radius, 1.5 * Math.PI, 0.5 * Math.PI, false);
    else
        context.arc(0, 0, (pie_d / 2) * radius, 0.5 * Math.PI, 1.5 * Math.PI, false);
    context.closePath();
    context.fill();
    context.restore();
    context = null;
}


if (cmk.dashboard.has_canvas_support()) {
    %(p)s
}
""" % {
                "x": int(pie_diameter / 2.0),
                "y": int(pie_diameter / 2.0),
                "d": pie_diameter,
                'p': '\n'.join(pie_parts)
            })
Пример #10
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"), class_="show_more_mode")
            html.th(_("Unhandled"))
            if show_stales and has_stale_objects:
                html.th(_("Stale"), class_="show_more_mode")
            html.close_tr()

            td_class = 'col4' if has_stale_objects else 'col3'

            html.open_tr()
            url = makeuri_contextless(request,
                                      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 = makeuri_contextless(
                    request,
                    getattr(row.views, ty) + context_vars,
                    filename="view.py",
                )
                html.open_td(class_=[
                    td_class, "states prob" if value != 0 else None,
                    "show_more_mode" if ty == "handled" else "basic"
                ])
                link(str(value), url)
                html.close_td()

            if show_stales and has_stale_objects:
                if row.views.stale:
                    url = makeuri_contextless(
                        request,
                        row.views.stale + context_vars,
                        filename="view.py",
                    )
                    html.open_td(class_=[
                        td_class, "states prob" if stales != 0 else None,
                        "show_more_mode"
                    ])
                    link(str(stales), url)
                    html.close_td()
                else:
                    html.td(html.render_span("0"), class_="show_more_mode")

            html.close_tr()
        html.close_table()
Пример #11
0
    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()
Пример #12
0
 def write_line(left, right):
     html.open_tr()
     html.td(left, class_="left")
     html.td(html.render_strong(right), class_="right")
     html.close_tr()
Пример #13
0
def show_file(site, host_name, file_name):
    int_filename = form_file_to_int(file_name)

    title = _("Logfiles of Host %s: %s") % (host_name, int_filename)
    breadcrumb = _show_file_breadcrumb(host_name, title)
    html.header(
        title, breadcrumb,
        _show_file_page_menu(breadcrumb, site, host_name, int_filename))

    if html.request.has_var(
            '_ack') and not html.request.var("_do_actions") == _("No"):
        do_log_ack(site, host_name, file_name)
        return

    try:
        log_chunks = parse_file(site,
                                host_name,
                                int_filename,
                                hidecontext=html.request.var(
                                    '_hidecontext', 'no') == 'yes')
    except Exception as e:
        if config.debug:
            raise
        html.show_error(_("Unable to show logfile: <b>%s</b>") % e)
        html.footer()
        return

    if log_chunks is None:
        html.show_error(_("The logfile does not exist on site."))
        html.footer()
        return

    if log_chunks == []:
        html.show_message(
            _("This logfile contains no unacknowledged messages."))
        html.footer()
        return

    html.open_div(id_="logwatch")
    for log in log_chunks:
        html.open_table(class_="groupheader")
        html.open_tr()
        html.td(form_level(log['level']), class_=form_level(log['level']))
        html.td(form_datetime(log['datetime']), class_="date")
        html.close_tr()
        html.close_table()

        html.open_table(class_=["section"])
        for line in log['lines']:
            html.open_tr(class_=line['class'])
            html.open_td(class_='lines')
            html.icon_button(
                analyse_url(site, host_name, int_filename, line['line']),
                _("Analyze this line"), "analyze")
            html.write_text(line['line'].replace(" ", "&nbsp;").replace(
                "\1", "<br>"))
            html.close_td()
            html.close_tr()

        html.close_table()

    html.close_div()
    html.footer()
Пример #14
0
def show_file(site, host_name, file_name):
    int_filename = form_file_to_int(file_name)

    html.header(_("Logfiles of Host %s: %s") % (host_name, file_name))
    html.begin_context_buttons()
    html.context_button(_("Services"), services_url(site, host_name),
                        'services')
    html.context_button(_("All Logfiles of Host"),
                        html.makeuri([('file', '')]))
    button_all_logfiles()
    html.context_button(_("Analyze patterns"),
                        analyse_url(site, host_name, file_name), 'analyze')

    if html.request.var('_hidecontext', 'no') == 'yes':
        hide_context_label = _('Show Context')
        hide_context_param = 'no'
        hide = True
    else:
        hide_context_label = _('Hide Context')
        hide_context_param = 'yes'
        hide = False

    try:
        log_chunks = parse_file(site, host_name, int_filename, hide)
    except Exception as e:
        if config.debug:
            raise
        html.end_context_buttons()
        html.show_error(_("Unable to show logfile: <b>%s</b>") % e)
        html.footer()
        return

    if log_chunks is None:
        html.end_context_buttons()
        html.show_error(_("The logfile does not exist."))
        html.footer()
        return

    if log_chunks == []:
        html.end_context_buttons()
        html.show_message(
            _("This logfile contains no unacknowledged messages."))
        html.footer()
        return

    ack_button(site, host_name, int_filename)
    html.context_button(hide_context_label,
                        html.makeuri([('_hidecontext', hide_context_param)]))

    html.end_context_buttons()

    html.open_div(id_="logwatch")
    for log in log_chunks:
        html.open_div(class_=["chunk"])
        html.open_table(class_=["section"])
        html.open_tr()
        html.td(form_level(log['level']), class_=form_level(log['level']))
        html.td(form_datetime(log['datetime']), class_="date")
        html.close_tr()
        html.close_table()

        for line in log['lines']:
            html.open_p(class_=line['class'])
            html.icon_button(
                analyse_url(site, host_name, file_name, line['line']),
                _("Analyze this line"), "analyze")
            html.write_text(line['line'].replace(" ", "&nbsp;").replace(
                "\1", "<br>"))
            html.close_p()

        html.close_div()

    html.close_div()
    html.footer()
Пример #15
0
    def render(self, rows, view, group_cells, cells, num_columns,
               show_checkboxes):
        repeat_heading_every = 20  # in case column_headers is "repeat"

        html.open_table(class_='data table')
        last_group = None
        odd = "odd"
        column = 1
        group_open = False
        num_cells = len(cells)
        if show_checkboxes:
            num_cells += 1

        if not group_cells and view.get("column_headers") != "off":
            self._show_header_line(cells, num_columns, show_checkboxes)

        rows_with_ids = [(row_id(view, row), row) for row in rows]
        groups, rows_with_ids = calculate_view_grouping_of_services(
            rows_with_ids, row_group_cells=group_cells)

        visible_row_number = 0
        group_hidden, num_grouped_rows = None, 0
        for index, row in rows_with_ids:
            # Show group header, if a new group begins. But only if grouping
            # is activated
            if group_cells:
                this_group = group_value(row, group_cells)
                if this_group != last_group:
                    if column != 1:  # not a the beginning of a new line
                        for _i in xrange(column - 1, num_columns):
                            html.td('', class_="gap")
                            html.td('', class_="fillup", colspan=num_cells)
                        html.close_tr()
                        column = 1

                    group_open = True
                    visible_row_number = 0

                    # paint group header, but only if it is non-empty
                    header_is_empty = True
                    for cell in group_cells:
                        _tdclass, content = cell.render(row)
                        if content:
                            header_is_empty = False
                            break

                    if not header_is_empty:
                        html.open_tr(class_="groupheader")
                        html.open_td(class_="groupheader",
                                     colspan=(num_cells * (num_columns + 2) +
                                              (num_columns - 1)))
                        html.open_table(class_="groupheader",
                                        cellspacing=0,
                                        cellpadding=0,
                                        border=0)
                        html.open_tr()
                        painted = False
                        for cell in group_cells:
                            if painted:
                                html.td(',&nbsp;')
                            painted = cell.paint(row)

                        html.close_tr()
                        html.close_table()
                        html.close_td()
                        html.close_tr()

                    # Table headers
                    if view.get("column_headers") != "off":
                        self._show_header_line(cells, num_columns,
                                               show_checkboxes)
                    last_group = this_group

            # Should we wrap over to a new line?
            if column >= num_columns + 1:
                html.close_tr()
                column = 1

            # At the beginning of the line? Beginn new line
            if column == 1:
                if view.get("column_headers") == "repeat":
                    if visible_row_number > 0 and visible_row_number % repeat_heading_every == 0:
                        self._show_header_line(cells, num_columns,
                                               show_checkboxes)
                visible_row_number += 1

                # In one-column layout we use the state of the service
                # or host - if available - to color the complete line
                if num_columns == 1:
                    # render state, if available through whole tr
                    if not row.get('service_description'):
                        state = row.get("host_state", 0)
                        if state > 0:
                            state += 1  # 1 is critical for hosts
                    else:
                        state = row.get("service_state", 0)
                else:
                    state = 0

                if index in groups:
                    group_spec, num_grouped_rows = groups[index]
                    group_hidden = grouped_row_title(index, group_spec,
                                                     num_grouped_rows, odd,
                                                     num_cells)
                    odd = "even" if odd == "odd" else "odd"

                css_classes = []

                hide = ""
                if num_grouped_rows > 0:
                    num_grouped_rows -= 1
                    if group_hidden:
                        hide = "display:none"

                if group_hidden is not None and num_grouped_rows == 0:
                    # last row in group
                    css_classes.append("group_end")
                    group_hidden = None

                odd = "even" if odd == "odd" else "odd"

                if num_columns > 1:
                    css_classes.append("multicolumn")
                css_classes += ["%s%d" % (odd, state)]

                html.open_tr(class_=["data"] + css_classes, style=hide)

            # Not first columns: Create one empty column as separator
            else:
                html.open_td(class_="gap")
                html.close_td()

            if show_checkboxes:
                render_checkbox_td(view, row, num_cells)

            last_cell = cells[-1]
            for cell in cells:
                cell.paint(row, is_last_cell=last_cell == cell)

            column += 1

        if group_open:
            for _i in xrange(column - 1, num_columns):
                html.td('', class_="gap")
                html.td('', class_="fillup", colspan=num_cells)
            html.close_tr()
        html.close_table()
        init_rowselect(view)
Пример #16
0
 def write_line(left, right, advanced):
     html.open_tr(class_="advanced" if advanced else "basic")
     html.td(left, class_="left")
     html.td(html.render_strong(right), class_="right")
     html.close_tr()
Пример #17
0
    def render(self, rows, view, group_cells, cells, num_columns,
               show_checkboxes):
        header_majorities = self._matrix_find_majorities_for_header(
            rows, group_cells)
        value_counts, row_majorities = self._matrix_find_majorities(
            rows, cells)

        painter_options = PainterOptions.get_instance()
        for groups, unique_row_ids, matrix_cells in \
                 create_matrices(rows, group_cells, cells, num_columns):

            # Paint the matrix. Begin with the group headers
            html.open_table(class_="data matrix")
            odd = "odd"
            for cell_nr, cell in enumerate(group_cells):
                odd = "even" if odd == "odd" else "odd"
                html.open_tr(class_="data %s0" % odd)
                html.open_td(class_="matrixhead")
                html.write(cell.title(use_short=False))
                html.close_td()
                for _group, group_row in groups:
                    tdclass, content = cell.render(group_row)
                    if cell_nr > 0:
                        gv = group_value(group_row, [cell])
                        majority_value = header_majorities.get(
                            cell_nr - 1, None)
                        if majority_value is not None and majority_value != gv:
                            tdclass += " minority"
                    html.open_td(class_=["left", tdclass])
                    html.write(content)
                    html.close_td()
                html.close_tr()

            # Now for each unique service^H^H^H^H^H^H ID column paint one row
            for rid in unique_row_ids:
                # Omit rows where all cells have the same values
                if painter_options.get("matrix_omit_uniform"):
                    at_least_one_different = False
                    for counts in value_counts[rid].values():
                        if len(counts) > 1:
                            at_least_one_different = True
                            break
                    if not at_least_one_different:
                        continue

                odd = "even" if odd == "odd" else "odd"
                html.open_tr(class_="data %s0" % odd)
                tdclass, content = cells[0].render(
                    matrix_cells[rid].values()[0])
                html.open_td(class_=["left", tdclass])
                html.write(content)
                html.close_td()

                # Now go through the groups and paint the rest of the
                # columns
                for group_id, group_row in groups:
                    cell_row = matrix_cells[rid].get(group_id)
                    if cell_row is None:
                        html.td('')
                    else:
                        if len(cells) > 2:
                            html.open_td(class_="cell")
                            html.open_table()

                        for cell_nr, cell in enumerate(cells[1:]):
                            tdclass, content = cell.render(cell_row)

                            gv = group_value(cell_row, [cell])
                            majority_value = row_majorities[rid].get(
                                cell_nr, None)
                            if majority_value is not None and majority_value != gv:
                                tdclass += " minority"

                            if len(cells) > 2:
                                html.open_tr()
                            html.open_td(class_=tdclass)
                            html.write(content)
                            html.close_td()
                            if len(cells) > 2:
                                html.close_tr()

                        if len(cells) > 2:
                            html.close_table()
                            html.close_td()
                html.close_tr()

            html.close_table()
Пример #18
0
    def show(self):
        if not watolib.is_wato_slave_site():
            if not config.wato_enabled:
                html.write_text(_("WATO is disabled."))
                return False

        user_folders = compute_foldertree()

        #
        # Render link target selection
        #
        selected_topic, selected_target = config.user.load_file(
            "foldertree", (_('Hosts'), 'allhosts'))

        topic_views = visuals_by_topic(
            list(views.get_permitted_views().items()) +
            list(dashboard.get_permitted_dashboards().items()))
        topics = [(t, t) for t, _s in topic_views]

        html.open_table()
        html.open_tr()
        html.td(_('Topic:'), class_="label")
        html.open_td()
        html.dropdown("topic",
                      topics,
                      deflt=selected_topic,
                      onchange='cmk.sidebar.wato_tree_topic_changed(this)')
        html.close_td()
        html.close_tr()

        html.open_tr()
        html.td(_("View:"), class_="label")
        html.open_td()

        for topic, view_list in topic_views:
            targets = []
            for t, title, name, is_view in view_list:
                if config.visible_views and name not in config.visible_views:
                    continue
                if config.hidden_views and name in config.hidden_views:
                    continue
                if t == topic:
                    if not is_view:
                        name = 'dashboard|' + name
                    targets.append((name, title))

            if topic != selected_topic:
                default = ''
                style = 'display:none'  # type: Optional[str]
            else:
                default = selected_target
                style = None
            html.dropdown(
                "target_%s" % topic,
                targets,
                deflt=default,
                onchange='cmk.sidebar.wato_tree_target_changed(this)',
                style=style)

        html.close_td()
        html.close_tr()
        html.close_table()

        # Now render the whole tree
        if user_folders:
            render_tree_folder("wato-hosts",
                               list(user_folders.values())[0],
                               'cmk.sidebar.wato_tree_click')
Пример #19
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(
                html.makeactionuri([(ActionHandler.stop_job_var, job_id)]),
                _("Stop this job"), "disable_test")
        if job_status.get("may_delete"):
            html.icon_button(
                html.makeactionuri([(ActionHandler.delete_job_var, job_id)]),
                _("Delete this job"), "delete")
        html.close_td()

        # Job ID
        html.open_td(css="job_id")
        uri = html.makeuri_contextless([("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(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")
Пример #20
0
    def _show_master_control_site(self, site_id: sites.SiteId,
                                  site_status_info: Dict[sites.SiteId, List],
                                  items: List[Tuple[str, str]]) -> None:
        site_state = sites.states().get(site_id)

        if not site_state:
            html.show_error(_("Site state is unknown"))
            return

        if site_state["state"] == "dead":
            html.show_error(site_state["exception"])
            return

        if site_state["state"] == "disabled":
            html.show_message(_("Site is disabled"))
            return

        if site_state["state"] == "unknown":
            if site_state.get("exception"):
                html.show_error(site_state["exception"])
            else:
                html.show_error(_("Site state is unknown"))
            return

        is_cmc = site_state["program_version"].startswith("Check_MK ")

        try:
            site_info = site_status_info[site_id]
        except KeyError:
            html.show_error(_("Site state is unknown"))
            return

        html.open_table(class_="master_control")
        for i, (colname, title) in enumerate(items):
            # Do not show event handlers on Checkmk Micro Core
            if is_cmc and title == _("Event handlers"):
                continue

            if not is_cmc and title == _("Alert handlers"):
                continue

            colvalue = site_info[i]
            url = makeactionuri_contextless(request,
                                            transactions, [
                                                ("site", site_id),
                                                ("switch", colname),
                                                ("state", "%d" %
                                                 (1 - colvalue)),
                                            ],
                                            filename="switch_master_state.py")
            onclick = "cmk.ajax.get_url('%s', cmk.utils.update_contents, 'snapin_master_control')" % url

            html.open_tr()
            html.td(title, class_="left")
            html.open_td()
            html.toggle_switch(
                enabled=colvalue,
                help_txt=_("Switch '%s' to '%s'") %
                (title, _("off") if colvalue else _("on")),
                onclick=onclick,
            )
            html.close_td()
            html.close_tr()

        html.close_table()
Пример #21
0
 def write_line(left, right, show_more):
     html.open_tr(class_="show_more_mode" if show_more else "basic")
     html.td(left, class_="left")
     html.td(html.render_strong(right), class_="right")
     html.close_tr()
Пример #22
0
    def _write_table(self, rows, actions_enabled, actions_visible, search_term):
        headinfo = _("1 row") if len(rows) == 1 else _("%d rows") % len(rows)
        html.javascript("cmk.utils.update_header_info(%s);" % json.dumps(headinfo))

        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 self.rows[0][2] != "header":
            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 self.options["searchable"]:
                html.open_div(class_="search")
                html.text_input("_%s_search" % table_id)
                html.button("_%s_submit" % table_id, _("Search"))
                html.button("_%s_reset" % table_id, _("Reset search"))
                html.set_focus("_%s_search" % table_id)
                html.close_div()

            if html.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_spec, css, state, _fixed, attrs) in enumerate(rows):
            if not css and "class_" in attrs:
                css = attrs.pop("class_")
            if not css and "class" in attrs:
                css = attrs.pop("class")

            # Intermediate header
            if state == "header":
                # Show the header only, if at least one (non-header) row follows
                if nr < len(rows) - 1 and rows[nr + 1][2] != "header":
                    html.open_tr(class_="groupheader")
                    html.open_td(colspan=num_cols)
                    html.open_h3()
                    html.write(row_spec)
                    html.close_h3()
                    html.close_td()
                    html.close_tr()

                    self._render_headers(actions_enabled, actions_visible, empty_columns)
                continue

            oddeven_name = "even" if (nr - 1) % 2 == 0 else "odd"

            html.open_tr(class_=["data",
                                 "%s%d" % (oddeven_name, state), css if css else None],
                         **attrs)
            for col_index, (cell_content, css_classes, colspan) in enumerate(row_spec):
                if self.options["omit_empty_columns"] and empty_columns[col_index]:
                    continue

                html.open_td(class_=css_classes if css_classes else None,
                             colspan=colspan if colspan else None)
                html.write(cell_content)
                html.close_td()
            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()
Пример #23
0
    def _write_table(self, rows, actions_enabled, actions_visible,
                     search_term):
        # type: (TableRows, bool, bool, Optional[str]) -> None
        headinfo = _("1 row") if len(rows) == 1 else _("%d rows") % len(rows)
        html.javascript("cmk.utils.update_header_info(%s);" %
                        json.dumps(headinfo))

        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 self.options["searchable"]:
                html.open_div(class_="search")
                html.text_input("_%s_search" % table_id)
                html.button("_%s_submit" % table_id, _("Search"))
                html.button("_%s_reset" % table_id, _("Reset search"))
                html.set_focus("_%s_search" % table_id)
                html.close_div()

            if html.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.open_h3()
                    html.write(row.title)
                    html.close_h3()
                    html.close_td()
                    html.close_tr()

                    self._render_headers(actions_enabled, actions_visible,
                                         empty_columns)
                continue

            oddeven_name = "even" if (nr - 1) % 2 == 0 else "odd"
            class_ = ["data", "%s%d" % (oddeven_name, row.state)]
            if row.css:
                class_.append(row.css)
            else:
                for k in ["class_", "class"]:
                    if k in row.row_attributes:
                        cls_spec = cast(CSSSpec, row.row_attributes.pop(k))
                        if isinstance(cls_spec, list):
                            class_.extend(
                                [c for c in cls_spec if c is not None])
                        elif cls_spec is not None:
                            class_.append(cls_spec)

            html.open_tr(class_=class_, **row.row_attributes)
            for col_index, cell in enumerate(row.cells):
                if self.options["omit_empty_columns"] and empty_columns[
                        col_index]:
                    continue

                html.open_td(class_=cell.css, colspan=cell.colspan)
                html.write(cell.content)
                html.close_td()
            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()
Пример #24
0
    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", part.css_class])
                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()