Example #1
0
    def update(self):
        import cmk.gui.sidebar as sidebar  # pylint: disable=import-outside-toplevel
        dashlet = self._dashlet_spec
        snapin = sidebar.snapin_registry.get(self._dashlet_spec['snapin'])
        if not snapin:
            raise MKUserError(None,
                              _('The configured element does not exist.'))
        snapin_instance = snapin()

        html.set_browser_reload(self.refresh_interval())
        html.html_head(_('Sidebar element'))
        html.open_body(class_="side", data_theme=theme.get())
        html.open_div(id_="check_mk_sidebar")
        html.open_div(id_="side_content")
        html.open_div(id_="snapin_container_%s" % dashlet['snapin'],
                      class_="snapin")
        html.open_div(id_="snapin_%s" % dashlet['snapin'], class_="content")
        styles = snapin_instance.styles()
        if styles:
            html.style(styles)
        snapin_instance.show()
        html.close_div()
        html.close_div()
        html.close_div()
        html.close_div()
        html.body_end()
Example #2
0
    def update(self):
        import cmk.gui.sidebar as sidebar
        dashlet = self._dashlet_spec
        snapin = sidebar.snapin_registry.get(self._dashlet_spec['snapin'])
        if not snapin:
            raise MKUserError(None, _('The configured snapin does not exist.'))
        snapin_instance = snapin()

        html.set_browser_reload(self.refresh_interval())
        html.html_head(_('Snapin Dashlet'))
        html.style('''
#side_content {
    height: auto;
    top: 0;
    padding-top: 4px;
    padding-left: 4px;
}
div.snapin:last-child {
    margin-bottom: 0;
}
div.snapin div.content {
    background-image: none;
    background-color: #508AA1;
}
div.snapin {
    margin: 0;
    padding: 0;
}
body.side {
    overflow-x: hidden;
    overflow-y: auto;
}''')
        html.open_body(class_="side")
        html.open_div(id_="check_mk_sidebar")
        html.open_div(id_="side_content")
        html.open_div(id_="snapin_container_%s" % dashlet['snapin'], class_="snapin")
        html.open_div(id_="snapin_%s" % dashlet['snapin'], class_="content")
        styles = snapin_instance.styles()
        if styles:
            html.style(styles)
        snapin_instance.show()
        html.close_div()
        html.close_div()
        html.close_div()
        html.close_div()
        html.body_end()
Example #3
0
    def show(self, title: Optional[str] = None, content: Optional['HTML'] = None) -> None:
        # TODO: Right now the method renders the full HTML page, i.e.
        # the header, sidebar, and page content. Ideallly we should
        # split this up. Possible solutions might be:
        #
        #     1. If we remove the page side.py the code for the header
        #        and the page content can be moved to the page index.py.
        #     2. Alternatively, we could extract a helper function that
        #        provides the header and body (without content). Then
        #        helper could then be used by index.py and side.py.
        #
        # In both cases this method would only render the sidebar
        # content afterwards.

        html.clear_default_javascript()
        html.html_head(title or _("Checkmk Sidebar"), javascripts=["side"])

        self._show_body_start()
        self._show_sidebar()
        self._show_page_content(content)

        html.body_end()
Example #4
0
def edit_annotation():
    site_id = html.request.var("anno_site") or ""
    hostname = html.request.get_str_input_mandatory("anno_host")
    service = html.request.var("anno_service") or None
    fromtime = html.request.get_float_input_mandatory("anno_from")
    untiltime = html.request.get_float_input_mandatory("anno_until")
    site_host_svc = (site_id, hostname, service)

    # Find existing annotation with this specification
    annotations = availability.load_annotations()
    annotation = availability.find_annotation(annotations, site_host_svc,
                                              fromtime, untiltime)

    if annotation:
        value = annotation.copy()
    else:
        value = {
            "from": fromtime,
            "until": untiltime,
            "text": "",
        }

    value["host"] = hostname
    value["service"] = service
    value["site"] = site_id

    if html.check_transaction():
        try:
            vs = _vs_annotation()
            value = vs.from_html_vars("_editanno")
            vs.validate_value(value, "_editanno")

            site_host_svc = (value["site"], value["host"], value["service"])
            del value["site"]
            del value["host"]
            value["date"] = time.time()
            value["author"] = config.user.id
            availability.update_annotations(site_host_svc,
                                            value,
                                            replace_existing=annotation)
            html.request.del_var("filled_in")
            return False
        except MKUserError as e:
            html.user_error(e)

    title = _("Edit annotation of ") + hostname
    if service:
        title += "/" + service

    html.body_start(title)
    html.top_heading(title)

    html.begin_context_buttons()
    html.context_button(_("Abort"), html.makeuri([("anno_host", "")]), "abort")
    html.end_context_buttons()

    html.begin_form("editanno", method="GET")
    _vs_annotation().render_input_as_form("_editanno", value)

    html.button("save", _("Save"))

    html.hidden_fields()
    html.end_form()

    html.bottom_footer()
    html.body_end()
    return True
Example #5
0
def render_bi_availability(title, aggr_rows):
    # type: (Text, Rows) -> None
    config.user.need_permission("general.see_availability")

    av_mode = html.request.get_ascii_input_mandatory("av_mode", "availability")
    avoptions = get_availability_options_from_url("bi")
    if av_mode == "timeline":
        title = _("Timeline of") + " " + title
    else:
        title = _("Availability of") + " " + title

    if html.output_format != "csv_export":
        html.body_start(title)
        html.top_heading(title)
        html.begin_context_buttons()
        html.toggle_button("avoptions", False, "painteroptions",
                           _("Configure details of the report"))
        html.context_button(_("Status View"),
                            html.makeuri([("mode", "status")]), "status")
        if config.reporting_available() and config.user.may(
                "general.reporting"):
            html.context_button(_("Export as PDF"),
                                html.makeuri([], filename="report_instant.py"),
                                "report")
        if config.user.may("general.csv_export"):
            html.context_button(
                _("Export as CSV"),
                html.makeuri([("output_format", "csv_export")]),
                "download_csv")

        if av_mode == "timeline":
            html.context_button(_("Availability"),
                                html.makeuri([("av_mode", "availability")]),
                                "availability")

        elif len(aggr_rows) == 1:
            aggr_name = aggr_rows[0]["aggr_name"]
            aggr_group = aggr_rows[0]["aggr_group"]
            timeline_url = html.makeuri([("av_mode", "timeline"),
                                         ("av_aggr_name", aggr_name),
                                         ("av_aggr_group", aggr_group)])
            html.context_button(_("Timeline"), timeline_url, "timeline")
        html.end_context_buttons()

        avoptions = render_availability_options("bi")

    if not html.has_user_errors():
        logrow_limit = avoptions["logrow_limit"]
        if logrow_limit == 0:
            livestatus_limit = None
        else:
            livestatus_limit = (len(aggr_rows) * logrow_limit)

        spans = []  # type: List[AVSpan]

        # iterate all aggregation rows
        timewarpcode = HTML()
        timewarp = html.request.get_integer_input("timewarp")

        has_reached_logrow_limit = False
        timeline_containers, fetched_rows = availability.get_timeline_containers(
            aggr_rows, avoptions, timewarp,
            livestatus_limit + 1 if livestatus_limit is not None else None)
        if livestatus_limit and fetched_rows > livestatus_limit:
            has_reached_logrow_limit = True

        for timeline_container in timeline_containers:
            tree = timeline_container.aggr_tree
            these_spans = timeline_container.timeline
            timewarp_tree_state = timeline_container.timewarp_state

            spans += these_spans

            # render selected time warp for the corresponding aggregation row (should be matched by only one)
            if timewarp and timewarp_tree_state:
                state, assumed_state, node, _subtrees = timewarp_tree_state
                eff_state = state
                if assumed_state is not None:
                    eff_state = assumed_state
                row = {
                    "aggr_tree": tree,
                    "aggr_treestate": timewarp_tree_state,
                    "aggr_state": state,  # state disregarding assumptions
                    "aggr_assumed_state":
                    assumed_state,  # is None, if there are no assumptions
                    "aggr_effective_state":
                    eff_state,  # is assumed_state, if there are assumptions, else real state
                    "aggr_name": node["title"],
                    "aggr_output": eff_state["output"],
                    "aggr_hosts": node["reqhosts"],
                    "aggr_function": node["func"],
                    "aggr_group": html.request.var("aggr_group"),
                }

                renderer = bi.FoldableTreeRendererTree(
                    row,
                    omit_root=False,
                    expansion_level=config.user.bi_expansion_level,
                    only_problems=False,
                    lazy=False)
                tdclass, htmlcode = renderer.css_class(), renderer.render()

                with html.plugged():
                    # TODO: SOMETHING IS WRONG IN HERE (used to be the same situation in original code!)
                    # FIXME: WHAT is wrong in here??

                    html.open_h3()
                    # render icons for back and forth
                    button_back_shown = False
                    button_forth_shown = False
                    if int(these_spans[0]["from"]) == timewarp:
                        html.disabled_icon_button("back_off")
                        button_back_shown = True

                    previous_span = None
                    for span in these_spans:
                        if not button_back_shown and int(
                                span["from"]
                        ) == timewarp and previous_span is not None:
                            html.icon_button(
                                html.makeuri([("timewarp",
                                               str(int(previous_span["from"])))
                                              ]), _("Jump one phase back"),
                                "back")
                            button_back_shown = True
                        # Multiple followup spans can have the same "from" time
                        # We only show one forth-arrow with an actual time difference
                        elif not button_forth_shown and previous_span and int(
                                previous_span["from"]) == timewarp and int(
                                    span["from"]) != timewarp:
                            html.icon_button(
                                html.makeuri([("timewarp",
                                               str(int(span["from"])))]),
                                _("Jump one phase forth"), "forth")
                            button_forth_shown = True
                        previous_span = span
                    if not button_forth_shown:
                        html.disabled_icon_button("forth_off")

                    html.write_text("   ")
                    html.icon_button(html.makeuri([("timewarp", "")]),
                                     _("Close Timewarp"), "closetimewarp")
                    html.write_text("%s %s" %
                                    (_("Timewarp to "),
                                     time.strftime("%Y-%m-%d %H:%M:%S",
                                                   time.localtime(timewarp))))
                    html.close_h3()

                    html.open_table(class_=["data", "table", "timewarp"])
                    html.open_tr(class_=["data", "odd0"])
                    html.open_td(class_=tdclass)
                    html.write_html(htmlcode)
                    html.close_td()
                    html.close_tr()
                    html.close_table()

                    timewarpcode += html.drain()

        # Note: 'spans_by_object' returns two arguments which are used by
        # all availability views but not by BI. There we have to take
        # only complete aggregations
        av_rawdata = availability.spans_by_object(spans, None)[0]
        av_data = availability.compute_availability("bi", av_rawdata,
                                                    avoptions)

        # If we abolish the limit we have to fetch the data again
        # with changed logrow_limit = 0, which means no limit
        if has_reached_logrow_limit:
            text = _(
                "Your query matched more than %d log entries. "
                "<b>Note:</b> The shown data does not necessarily reflect the "
                "matched entries and the result might be incomplete. "
            ) % avoptions["logrow_limit"]
            text += html.render_a(_('Repeat query without limit.'),
                                  html.makeuri([("_unset_logrow_limit", "1")]))
            html.show_warning(text)

        if html.output_format == "csv_export" and config.user.may(
                "general.csv_export"):
            _output_csv("bi", av_mode, av_data, avoptions)
            return

        html.write(timewarpcode)
        do_render_availability("bi", av_rawdata, av_data, av_mode, None,
                               avoptions)

    html.bottom_footer()
    html.body_end()
Example #6
0
def render_availability_page(view, filterheaders):
    # type: (View, FilterHeaders) -> None
    config.user.need_permission("general.see_availability")

    if handle_edit_annotations():
        return

    # We make reports about hosts, services or BI aggregates
    if "service" in view.datasource.infos:
        what = "service"
    elif "aggr_name" in view.datasource.infos:
        what = "bi"
    else:
        what = "host"

    avoptions = get_availability_options_from_url(what)
    time_range, range_title = avoptions["range"]

    # We have two display modes:
    # - Show availability table (stats) "table"
    # - Show timeline                   "timeline"
    # --> controlled by URL variable "av_mode"
    av_mode = html.request.get_ascii_input_mandatory("av_mode", "table")

    if av_mode == "timeline":
        title = _("Availability Timeline")
    else:
        title = _("Availability")

    # This is combined with the object selection
    # - Show all objects
    # - Show one specific object
    # --> controlled by URL variables "av_site", "av_host" and "av_service"
    # --> controlled by "av_aggr" in case of BI aggregate
    title += " - "
    av_object = None  # type: AVObjectSpec
    if html.request.var("av_host"):
        av_object = (html.request.get_str_input_mandatory("av_site"),
                     html.request.get_str_input_mandatory("av_host"),
                     html.request.get_unicode_input_mandatory("av_service"))
        title += av_object[1]
        if av_object[2]:
            title += " - " + av_object[2]
    elif html.request.var("av_aggr"):
        av_object = (None, None,
                     html.request.get_unicode_input_mandatory("av_aggr"))
        title += av_object[2]
    else:
        title += view_title(view.spec)

    # Deletion must take place before computation, since it affects the outcome
    with html.plugged():
        handle_delete_annotations()
        confirmation_html_code = html.drain()

    # Now compute all data, we need this also for CSV export
    if not html.has_user_errors():
        include_long_output = av_mode == "timeline" \
                and "timeline_long_output" in avoptions["labelling"]
        av_rawdata, has_reached_logrow_limit = availability.get_availability_rawdata(
            what,
            view.context,
            filterheaders,
            view.only_sites,
            av_object=av_object,
            include_output=av_mode == "timeline",
            include_long_output=include_long_output,
            avoptions=avoptions)
        av_data = availability.compute_availability(what, av_rawdata,
                                                    avoptions)

    # Do CSV ouput
    if html.output_format == "csv_export" and config.user.may(
            "general.csv_export"):
        _output_csv(what, av_mode, av_data, avoptions)
        return

    title += " - " + range_title

    if display_options.enabled(display_options.H):
        html.body_start(title, force=True)

    if display_options.enabled(display_options.T):
        html.top_heading(title)

    html.write(confirmation_html_code)

    # Remove variables for editing annotations, otherwise they will make it into the uris
    html.request.del_vars("anno_")
    if html.request.var("filled_in") == "editanno":
        html.request.del_var("filled_in")

    if display_options.enabled(display_options.B):
        html.begin_context_buttons()
        html.toggle_button(
            "avoptions",
            html.has_user_errors(),
            "painteroptions",
            _("Configure details of the report"),
        )
        html.context_button(
            _("Status View"),
            html.makeuri([("mode", "status")]),
            "status",
        )
        if config.reporting_available() and config.user.may(
                "general.reporting"):
            html.context_button(
                _("Export as PDF"),
                html.makeuri([], filename="report_instant.py"),
                "report",
            )

        if config.user.may("general.csv_export"):
            html.context_button(
                _("Export as CSV"),
                html.makeuri([("output_format", "csv_export")]),
                "download_csv",
            )

        if av_mode == "timeline" or av_object:
            html.context_button(
                _("Availability"),
                html.makeuri([("av_mode", "availability"), ("av_host", ""),
                              ("av_aggr", "")]),
                "availability",
            )
        elif not av_object:
            html.context_button(
                _("Timeline"),
                html.makeuri([("av_mode", "timeline")]),
                "timeline",
            )
        elif av_mode == "timeline" and what != "bi":
            history_url = availability.history_url_of(av_object, time_range)
            html.context_button(
                _("History"),
                history_url,
                "history",
            )

        html.end_context_buttons()

    # Render the avoptions again to get the HTML code, because the HTML vars have changed
    # above (anno_ and editanno_ has been removed, which must not be part of the form
    avoptions = render_availability_options(what)

    if not html.has_user_errors():
        # If we abolish the limit we have to fetch the data again
        # with changed logrow_limit = 0, which means no limit
        if has_reached_logrow_limit:
            text = _(
                "Your query matched more than %d log entries. "
                "<b>Note:</b> The number of shown rows does not necessarily reflect the "
                "matched entries and the result might be incomplete. "
            ) % avoptions["logrow_limit"]
            text += html.render_a(
                _('Repeat query without limit.'),
                html.makeuri([("_unset_logrow_limit", "1"),
                              ("avo_logrow_limit", 0)]))
            html.show_warning(text)

        do_render_availability(what, av_rawdata, av_data, av_mode, av_object,
                               avoptions)

    if display_options.enabled(display_options.Z):
        html.bottom_footer()

    if display_options.enabled(display_options.H):
        html.body_end()
Example #7
0
    def show(self,
             title: Optional[str] = None,
             content: Optional[HTML] = None) -> None:
        # TODO: Right now the method renders the full HTML page, i.e.
        # the header, sidebar, and page content. Ideallly we should
        # split this up. Possible solutions might be:
        #
        #     1. If we remove the page side.py the code for the header
        #        and the page content can be moved to the page index.py.
        #     2. Alternatively, we could extract a helper function that
        #        provides the header and body (without content). Then
        #        helper could then be used by index.py and side.py.
        #
        # In both cases this method would only render the sidebar
        # content afterwards.
        if config.sidebar_notify_interval is not None:
            interval = config.sidebar_notify_interval
        else:
            interval = 'null'

        html.clear_default_javascript()
        if title is None:
            title = _("Check_MK Sidebar")
        html.html_head(title, javascripts=["side"])

        body_classes = ['side']
        if config.screenshotmode:
            body_classes.append("screenshotmode")

        if not config.user.may("general.see_sidebar"):
            html.open_body(class_=body_classes)
            html.div("", id_="check_mk_sidebar")
        else:
            html.open_body(
                class_=body_classes,
                onload=
                'cmk.sidebar.initialize_scroll_position(); cmk.sidebar.set_sidebar_size(); cmk.sidebar.init_messages(%s);'
                % interval,
                onunload="cmk.sidebar.store_scroll_position()")
            html.open_div(id_="check_mk_sidebar")

            self._sidebar_head()
            user_config = UserSidebarConfig(config.user, config.sidebar)
            refresh_snapins = []
            restart_snapins = []
            static_snapins = []

            html.open_div(
                class_="scroll" if config.sidebar_show_scrollbar else None,
                id_="side_content")
            for snapin in user_config.snapins:
                name = snapin.snapin_type.type_name()

                # Performs the initial rendering and might return an optional refresh url,
                # when the snapin contents are refreshed from an external source
                refresh_url = self.render_snapin(snapin)

                if snapin.snapin_type.refresh_regularly():
                    refresh_snapins.append([name, refresh_url])
                elif snapin.snapin_type.refresh_on_restart():
                    refresh_snapins.append([name, refresh_url])
                    restart_snapins.append(name)
                else:
                    static_snapins.append(name)

            html.close_div()
            self._sidebar_foot(user_config)
            html.close_div()

            html.javascript(
                "cmk.sidebar.initialize_sidebar(%0.2f, %s, %s, %s);\n" % (
                    config.sidebar_update_interval,
                    json.dumps(refresh_snapins),
                    json.dumps(restart_snapins),
                    json.dumps(static_snapins),
                ))

        html.open_div(id_="content_area")
        if content is not None:
            html.write(content)
        html.close_div()

        html.body_end()
Example #8
0
    def show(self):
        # type: () -> None
        if not config.user.may("general.see_sidebar"):
            return None
        if config.sidebar_notify_interval is not None:
            interval = config.sidebar_notify_interval
        else:
            interval = 'null'
        html.clear_default_javascript()
        html.html_head(_("Check_MK Sidebar"), javascripts=["side"])
        html.write('<body class="side')
        if config.screenshotmode:
            html.write(" screenshotmode")
        html.write(
            '" onload="cmk.sidebar.initialize_scroll_position(); cmk.sidebar.set_sidebar_size(); cmk.sidebar.init_messages(%s);" '
            'onunload="cmk.sidebar.store_scroll_position()">\n' % interval)
        html.open_div(id_="check_mk_sidebar")

        self._sidebar_head()
        user_config = UserSidebarConfig(config.user, config.sidebar)
        refresh_snapins = []
        restart_snapins = []

        html.open_div(class_="scroll" if config.sidebar_show_scrollbar else None,
                      id_="side_content")
        for snapin in user_config.snapins:
            name = snapin.snapin_type.type_name()

            # Performs the initial rendering and might return an optional refresh url,
            # when the snapin contents are refreshed from an external source
            refresh_url = self.render_snapin(snapin)

            if snapin.snapin_type.refresh_regularly():
                refresh_snapins.append([name, refresh_url])

            elif snapin.snapin_type.refresh_on_restart():
                refresh_snapins.append([name, refresh_url])
                restart_snapins.append(name)

        html.close_div()
        self._sidebar_foot(user_config)
        html.close_div()

        html.write("<script language=\"javascript\">\n")
        if restart_snapins:
            html.write("cmk.sidebar.set_sidebar_restart_time(%s);\n" % time.time())
        html.write("cmk.sidebar.set_sidebar_update_interval(%0.2f);\n" %
                   config.sidebar_update_interval)
        html.write("cmk.sidebar.register_edge_listeners();\n")
        html.write("cmk.sidebar.set_sidebar_size();\n")
        html.write("cmk.sidebar.set_refresh_snapins(%s);\n" % json.dumps(refresh_snapins))
        html.write("cmk.sidebar.set_restart_snapins(%s);\n" % json.dumps(restart_snapins))
        html.write("cmk.sidebar.execute_sidebar_scheduler();\n")
        html.write("cmk.sidebar.register_event_handlers();\n")
        html.write("window.onresize = function() { cmk.sidebar.set_sidebar_size(); };\n")
        html.write(
            "if (cmk.sidebar.is_content_frame_accessible()) { cmk.sidebar.update_content_location(); };\n"
        )
        html.write("</script>\n")

        html.body_end()