Esempio n. 1
0
    def _add_cell(
        self,
        title: 'HTMLContent' = "",
        text: 'HTMLContent' = "",
        css: 'CSSSpec' = None,
        help_txt: Optional[str] = None,
        colspan: Optional[int] = None,
        sortable: bool = True,
    ):
        if isinstance(text, HTML):
            content = text
        else:
            content = escape_html_permissive(str(text) if not isinstance(text, str) else text)

        htmlcode: HTML = content + HTML(output_funnel.drain())

        if isinstance(title, HTML):
            header_title = title
        else:
            if title is None:
                title = ""
            header_title = escape_html_permissive(
                str(title) if not isinstance(title, str) else title)

        if self.options["collect_headers"] is True:
            # small helper to make sorting introducion easier. Cells which contain
            # buttons are never sortable
            if css and 'buttons' in css and sortable:
                sortable = False
            self.headers.append(
                TableHeader(title=header_title, css=css, help_txt=help_txt, sortable=sortable))

        current_row = self.rows[-1]
        assert isinstance(current_row, TableRow)
        current_row.cells.append(CellSpec(htmlcode, css, colspan))
Esempio n. 2
0
def render_werk_title(werk) -> HTML:
    title = werk["title"]
    # if the title begins with the name or names of check plugins, then
    # we link to the man pages of those checks
    if ":" in title:
        parts = title.split(":", 1)
        return insert_manpage_links(parts[0]) + escape_html_permissive(":" + parts[1])
    return escape_html_permissive(title)
Esempio n. 3
0
    def show(self) -> None:
        html.open_table(cellspacing="0", class_="sitestate")

        sites.update_site_states_from_dead_sites()

        for sitename, _sitealias in sites.sorted_sites():
            site = sites.get_site_config(sitename)

            state = sites.states().get(sitename,
                                       sites.SiteStatus({})).get("state")

            if state is None:
                state = "missing"
                switch = "missing"
                text = escape_html_permissive(sitename)

            else:
                if state == "disabled":
                    switch = "on"
                    text = escape_html_permissive(site["alias"])
                else:
                    switch = "off"
                    text = render_link(
                        site["alias"],
                        "view.py?view_name=sitehosts&site=%s" % sitename)

            html.open_tr()
            html.td(text, class_="left")
            html.open_td(class_="state")
            if switch == "missing":
                html.status_label(content=state,
                                  status=state,
                                  title=_("Site is missing"))
            else:
                url = makeactionuri_contextless(
                    request,
                    transactions,
                    [
                        ("_site_switch", "%s:%s" % (sitename, switch)),
                    ],
                    filename="switch_site.py",
                )
                html.status_label_button(
                    content=state,
                    status=state,
                    title=_("enable this site")
                    if state == "disabled" else _("disable this site"),
                    onclick="cmk.sidebar.switch_site(%s)" % (json.dumps(url)),
                )
            html.close_tr()
        html.close_table()
Esempio n. 4
0
def mk_eval(s: Union[bytes, str]) -> Any:
    try:
        return ast.literal_eval(base64.b64decode(s).decode())
    except Exception:
        raise MKGeneralException(
            _("Unable to parse provided data: %s") %
            escape_html_permissive(repr(s)))
Esempio n. 5
0
    def action(self) -> ActionResult:
        if request.var("_reset"):
            if not transactions.check_transaction():
                return None

            try:
                del self._current_settings[self._varname]
            except KeyError:
                pass

            msg = escape_html_permissive(
                _("Resetted configuration variable %s to its default.") %
                self._varname)
        else:
            new_value = self._valuespec.from_html_vars("ve")
            self._valuespec.validate_value(new_value, "ve")
            self._current_settings[self._varname] = new_value
            msg = HTML(
                _("Changed global configuration variable %s to %s.") % (
                    escaping.escape_attribute(self._varname),
                    self._valuespec.value_to_html(new_value),
                ))

        self._save()
        watolib.add_change(
            "edit-configvar",
            msg,
            sites=self._affected_sites(),
            domains=[self._config_variable.domain()],
            need_restart=self._config_variable.need_restart(),
        )

        return redirect(self._back_url())
Esempio n. 6
0
def query_limit_exceeded_warn(limit: Optional[int],
                              user_config: LoggedInUser) -> None:
    """Compare query reply against limits, warn in the GUI about incompleteness"""
    text = HTML(_("Your query produced more than %d results. ") % limit)

    if request.get_ascii_input(
            "limit",
            "soft") == "soft" and user_config.may("general.ignore_soft_limit"):
        text += html.render_a(
            _("Repeat query and allow more results."),
            target="_self",
            href=makeuri(request, [("limit", "hard")]),
        )
    elif request.get_ascii_input("limit") == "hard" and user_config.may(
            "general.ignore_hard_limit"):
        text += html.render_a(
            _("Repeat query without limit."),
            target="_self",
            href=makeuri(request, [("limit", "none")]),
        )

    text += escaping.escape_html_permissive(" " + _(
        "<b>Note:</b> the shown results are incomplete and do not reflect the sort order."
    ))
    html.show_warning(text)
Esempio n. 7
0
def text_with_links_to_user_translated_html(
    elements: Iterable[Tuple[str, Optional[str]]],
    separator: str = "",
) -> HTML:
    return HTML(separator).join(
        html.render_a(user_translation, href=url
                      ) if url else escape_html_permissive(user_translation)
        for txt, url in elements for user_translation in [_u(txt)] if txt)
Esempio n. 8
0
def test_escape_html_permissive() -> None:
    assert isinstance(escaping.escape_html_permissive(""), HTML)
    assert str(escaping.escape_html_permissive("")) == ""
    assert str(escaping.escape_html_permissive("<script>")) == "&lt;script&gt;"
    assert str(escaping.escape_html_permissive("<b>")) == "<b>"
Esempio n. 9
0
 def title(self):
     if self._new:
         return _("Add LDAP connection")
     assert self._connection_id is not None
     return _("Edit LDAP connection: %s") % escape_html_permissive(
         self._connection_id)
Esempio n. 10
0
    def _show_patterns(self):
        import cmk.gui.logwatch as logwatch
        collection = watolib.SingleRulesetRecursively("logwatch_rules")
        collection.load()
        ruleset = collection.get("logwatch_rules")

        html.h3(_('Logfile patterns'))
        if ruleset.is_empty():
            html.open_div(class_="info")
            html.write_text('There are no logfile patterns defined. You may create '
                            'logfile patterns using the <a href="%s">Rule Editor</a>.' %
                            watolib.folder_preserving_link([
                                ('mode', 'edit_ruleset'),
                                ('varname', 'logwatch_rules'),
                            ]))
            html.close_div()

        # Loop all rules for this ruleset
        already_matched = False
        abs_rulenr = 0
        for folder, rulenr, rule in ruleset.get_rules():
            # Check if this rule applies to the given host/service
            if self._hostname:
                service_desc = self._get_service_description(self._hostname, "logwatch", self._item)

                # If hostname (and maybe filename) try match it
                rule_matches = rule.matches_host_and_item(watolib.Folder.current(), self._hostname,
                                                          self._item, service_desc)
            else:
                # If no host/file given match all rules
                rule_matches = True

            with foldable_container(treename="rule",
                                    id_=str(abs_rulenr),
                                    isopen=True,
                                    title=HTML("<b>Rule #%d</b>" % (abs_rulenr + 1)),
                                    indent=False), table_element("pattern_editor_rule_%d" %
                                                                 abs_rulenr,
                                                                 sortable=False,
                                                                 css="logwatch") as table:
                abs_rulenr += 1

                # TODO: What's this?
                pattern_list = rule.value
                if isinstance(pattern_list, dict):
                    pattern_list = pattern_list["reclassify_patterns"]

                # Each rule can hold no, one or several patterns. Loop them all here
                for state, pattern, comment in pattern_list:
                    match_class = ''
                    disp_match_txt = HTML('')
                    match_img = ''
                    if rule_matches:
                        # Applies to the given host/service
                        matched = re.search(pattern, self._match_txt)
                        if matched:

                            # Prepare highlighted search txt
                            match_start = matched.start()
                            match_end = matched.end()
                            disp_match_txt = escape_html_permissive(self._match_txt[:match_start]) \
                                             + html.render_span(self._match_txt[match_start:match_end], class_="match")\
                                             + escape_html_permissive(self._match_txt[match_end:])

                            if not already_matched:
                                # First match
                                match_class = 'match first'
                                match_img = 'match'
                                match_title = _(
                                    'This logfile pattern matches first and will be used for '
                                    'defining the state of the given line.')
                                already_matched = True
                            else:
                                # subsequent match
                                match_class = 'match'
                                match_img = 'imatch'
                                match_title = _(
                                    'This logfile pattern matches but another matched first.')
                        else:
                            match_img = 'nmatch'
                            match_title = _('This logfile pattern does not match the given string.')
                    else:
                        # rule does not match
                        match_img = 'nmatch'
                        match_title = _('The rule conditions do not match.')

                    table.row()
                    table.cell(_('Match'))
                    html.icon("rule%s" % match_img, match_title)

                    cls: List[str] = []
                    if match_class == 'match first':
                        cls = ['state%d' % logwatch.level_state(state), 'fillbackground']
                    table.cell(_('State'), html.render_span(logwatch.level_name(state)), css=cls)
                    table.cell(_('Pattern'), html.render_tt(pattern))
                    table.cell(_('Comment'), comment)
                    table.cell(_('Matched line'), disp_match_txt)

                table.row(fixed=True)
                table.cell(colspan=5)
                edit_url = watolib.folder_preserving_link([
                    ("mode", "edit_rule"),
                    ("varname", "logwatch_rules"),
                    ("rulenr", rulenr),
                    ("item", watolib.mk_repr(self._item).decode()),
                    ("rule_folder", folder.path()),
                    ("rule_id", rule.id),
                ])
                html.icon_button(edit_url, _("Edit this rule"), "edit")
Esempio n. 11
0
def _process_notify_message(msg):
    msg["id"] = utils.gen_id()
    msg["time"] = time.time()

    if isinstance(msg["dest"], str):
        dest_what = msg["dest"]
    else:
        dest_what = msg["dest"][0]

    if dest_what == "broadcast":
        recipients = list(config.multisite_users.keys())
    elif dest_what == "online":
        recipients = userdb.get_online_user_ids()
    elif dest_what == "list":
        recipients = msg["dest"][1]
    else:
        recipients = []

    num_recipients = len(recipients)

    num_success = {}
    for method in msg["methods"]:
        num_success[method] = 0

    # Now loop all notitification methods to send the notifications
    errors: Dict[str, List[Tuple]] = {}
    for user_id in recipients:
        for method in msg["methods"]:
            try:
                handler = _notify_methods()[method]["handler"]
                handler(user_id, msg)
                num_success[method] = num_success[method] + 1
            except MKInternalError as e:
                errors.setdefault(method, []).append((user_id, e))

    message = escape_html_permissive(_("The notification has been sent via"))
    message += html.render_br()

    parts = []
    for method in msg["methods"]:
        parts.append(
            html.render_tr(
                html.render_td(_notify_methods()[method]["title"])
                + html.render_td(
                    _("to %d of %d recipients") % (num_success[method], num_recipients)
                )
            )
        )
    message += html.render_table(HTML().join(parts))

    message += html.render_p(_("Sent notification to: %s") % ", ".join(recipients))
    message += html.render_a(_("Back to previous page"), href=makeuri(request, []))
    html.show_message(message)

    if errors:
        error_message = HTML()
        for method, method_errors in errors.items():
            error_message += _("Failed to send %s notifications to the following users:") % method
            table_rows = HTML()
            for user_id, exception in method_errors:
                table_rows += html.render_tr(
                    html.render_td(html.render_tt(user_id)) + html.render_td(exception)
                )
            error_message += html.render_table(table_rows) + html.render_br()
        html.show_error(error_message)
Esempio n. 12
0
def parse_file(site, host_name, file_name, hidecontext=False):
    log_chunks: List[Dict[str, Any]] = []
    try:
        chunk: Optional[Dict[str, Any]] = None
        lines = get_logfile_lines(site, host_name, file_name)
        if lines is None:
            return None
        # skip hash line. this doesn't exist in older files
        while lines and lines[0].startswith('#'):
            lines = lines[1:]

        for line in lines:
            line = line.strip()
            if line == '':
                continue

            if line[:3] == '<<<':  # new chunk begins
                log_lines: List[Dict[str, Any]] = []
                chunk = {'lines': log_lines}
                log_chunks.append(chunk)

                # New header line
                date, logtime, level = line[3:-3].split(' ')

                # Save level as integer to make it better comparable
                if level == 'CRIT':
                    chunk['level'] = 2
                elif level == 'WARN':
                    chunk['level'] = 1
                elif level == 'OK':
                    chunk['level'] = 0
                else:
                    chunk['level'] = 0

                # Gather datetime object
                # Python versions below 2.5 don't provide datetime.datetime.strptime.
                # Use the following instead:
                #chunk['datetime'] = datetime.datetime.strptime(date + ' ' + logtime, "%Y-%m-%d %H:%M:%S")
                chunk['datetime'] = datetime.datetime(
                    *time.strptime(date + ' ' +
                                   logtime, "%Y-%m-%d %H:%M:%S")[0:5])

            elif chunk:  # else: not in a chunk?!
                # Data line
                line_display = line[2:]

                # Classify the line for styling
                if line[0] == 'W':
                    line_level = 1
                    line_class = 'WARN'

                elif line[0] == 'u':
                    line_level = 1
                    line_class = 'WARN'

                elif line[0] == 'C':
                    line_level = 2
                    line_class = 'CRIT'

                elif line[0] == 'O':
                    line_level = 0
                    line_class = 'OK'

                elif not hidecontext:
                    line_level = 0
                    line_class = 'context'

                else:
                    continue  # ignore this line

                log_lines.append({
                    'level': line_level,
                    'class': line_class,
                    'line': line_display
                })
    except Exception as e:
        if config.debug:
            raise
        raise MKGeneralException(
            escape_html_permissive(
                _("Cannot parse log file %s: %s") % (file_name, e)))

    return log_chunks
Esempio n. 13
0
    def _preview(self) -> None:
        html.begin_form("preview", method="POST")
        self._preview_form()

        attributes = self._attribute_choices()

        # first line could be missing in situation of import error
        csv_reader = self._open_csv_file()
        if not csv_reader:
            return  # don't try to show preview when CSV could not be read

        html.h2(_("Preview"))
        attribute_list = "<ul>%s</ul>" % "".join(
            ["<li>%s (%s)</li>" % a for a in attributes if a[0] is not None])
        html.help(
            _("This list shows you the first 10 rows from your CSV file in the way the import is "
              "currently parsing it. If the lines are not splitted correctly or the title line is "
              "not shown as title of the table, you may change the import settings above and try "
              "again.") + "<br><br>" +
            _("The first row below the titles contains fields to specify which column of the "
              "CSV file should be imported to which attribute of the created hosts. The import "
              "progress is trying to match the columns to attributes automatically by using the "
              "titles found in the title row (if you have some). "
              "If you use the correct titles, the attributes can be mapped automatically. The "
              "currently available attributes are:") + attribute_list +
            _("You can change these assignments according to your needs and then start the "
              "import by clicking on the <i>Import</i> button above."))

        # Wenn bei einem Host ein Fehler passiert, dann wird die Fehlermeldung zu dem Host angezeigt, so dass man sehen kann, was man anpassen muss.
        # Die problematischen Zeilen sollen angezeigt werden, so dass man diese als Block in ein neues CSV-File eintragen kann und dann diese Datei
        # erneut importieren kann.
        if self._has_title_line:
            try:
                headers = list(next(csv_reader))
            except StopIteration:
                headers = []  # nope, there is no header
        else:
            headers = []

        rows = list(csv_reader)

        # Determine how many columns should be rendered by using the longest column
        num_columns = max([len(r) for r in [headers] + rows])

        with table_element(sortable=False,
                           searchable=False,
                           omit_headers=not self._has_title_line) as table:

            # Render attribute selection fields
            table.row()
            for col_num in range(num_columns):
                header = headers[col_num] if len(headers) > col_num else None
                table.cell(escape_html_permissive(header))
                attribute_varname = "attribute_%d" % col_num
                if request.var(attribute_varname):
                    attribute_method = request.get_ascii_input_mandatory(
                        attribute_varname)
                else:
                    attribute_method = self._try_detect_default_attribute(
                        attributes, header)
                    request.del_var(attribute_varname)

                html.dropdown("attribute_%d" % col_num,
                              attributes,
                              deflt=attribute_method,
                              autocomplete="off")

            # Render sample rows
            for row in rows:
                table.row()
                for cell in row:
                    table.cell(None, cell)

        html.end_form()
Esempio n. 14
0
def _process_message_message(msg):
    msg["id"] = utils.gen_id()
    msg["time"] = time.time()

    if isinstance(msg["dest"], str):
        dest_what = msg["dest"]
    else:
        dest_what = msg["dest"][0]

    if dest_what == "all_users":
        recipients = list(config.multisite_users.keys())
    elif dest_what == "online":
        recipients = userdb.get_online_user_ids()
    elif dest_what == "list":
        recipients = msg["dest"][1]
    else:
        recipients = []

    num_recipients = len(recipients)

    num_success: Dict[str, int] = {}
    for method in msg["methods"]:
        num_success[method] = 0

    # Now loop all messaging methods to send the messages
    errors: Dict[str, List[Tuple]] = {}
    for user_id in recipients:
        for method in msg["methods"]:
            try:
                handler = _messaging_methods()[method]["handler"]
                handler(user_id, msg)
                num_success[method] = num_success[method] + 1
            except MKInternalError as e:
                errors.setdefault(method, []).append((user_id, e))

    message = escape_html_permissive(
        _("The message has successfully been sent..."))
    message += html.render_br()

    parts = []
    for method in msg["methods"]:
        parts.append(
            html.render_li(
                _messaging_methods()[method]["confirmation_title"] +
                (_(" for all recipients.") if num_success[method] ==
                 num_recipients else _(" for %d of %d recipients.") %
                 (num_success[method], num_recipients))))

    message += html.render_ul(HTML().join(parts))
    message += html.render_p(_("Recipients: %s") % ", ".join(recipients))
    html.show_message(message)

    if errors:
        error_message = HTML()
        for method, method_errors in errors.items():
            error_message += _(
                "Failed to send %s messages to the following users:") % method
            table_rows = HTML()
            for user_id, exception in method_errors:
                table_rows += html.render_tr(
                    html.render_td(html.render_tt(user_id)) +
                    html.render_td(str(exception)))
            error_message += html.render_table(table_rows) + html.render_br()
        html.show_error(error_message)
Esempio n. 15
0
 def title(self):
     if self._search:
         return _("Global settings matching '%s'") % escape_html_permissive(
             self._search)
     return _("Global settings")
Esempio n. 16
0
    def _show_configuration_variables(self) -> None:
        search = self._search

        at_least_one_painted = False
        html.open_div(class_="globalvars")
        for group, config_variables in self.iter_all_configuration_variables():
            header_is_painted = False  # needed for omitting empty groups

            for config_variable in config_variables:
                varname = config_variable.ident()
                valuespec = config_variable.valuespec()

                if self._show_only_modified and varname not in self._current_settings:
                    continue

                help_text = valuespec.help() or ""
                title_text = valuespec.title() or ""

                if (search and search not in group.title().lower() and search
                        not in config_variable.domain().ident().lower()
                        and search not in varname
                        and search not in help_text.lower()
                        and search not in title_text.lower()):
                    continue  # skip variable when search is performed and nothing matches
                at_least_one_painted = True

                if not header_is_painted:
                    # always open headers when searching
                    forms.header(group.title(),
                                 isopen=search or self._show_only_modified)
                    header_is_painted = True

                default_value = self._default_values[varname]

                edit_url = watolib.folder_preserving_link([
                    ("mode", self.edit_mode_name),
                    ("varname", varname),
                    ("site", request.var("site", "")),
                ])
                title = html.render_a(
                    title_text,
                    href=edit_url,
                    class_="modified"
                    if varname in self._current_settings else None,
                    title=escaping.strip_tags(help_text),
                )

                if varname in self._current_settings:
                    value = self._current_settings[varname]
                elif varname in self._global_settings:
                    value = self._global_settings[varname]
                else:
                    value = default_value

                try:
                    to_text = valuespec.value_to_html(value)
                    if isinstance(to_text, str):
                        to_text = escape_html_permissive(to_text)
                except Exception:
                    logger.exception("error converting %r to text", value)
                    to_text = html.render_error(
                        _("Failed to render value: %r") % value)

                # Is this a simple (single) value or not? change styling in these cases...
                simple = True
                if "\n" in to_text or "<td>" in to_text:
                    simple = False
                forms.section(title, simple=simple)

                if varname in self._current_settings:
                    modified_cls: Optional[str] = "modified"
                    value_title: Optional[str] = _(
                        "This option has been modified.")
                elif varname in self._global_settings:
                    modified_cls = "modified globally"
                    value_title = _(
                        "This option has been modified in global settings.")
                else:
                    modified_cls = None
                    value_title = None

                if is_a_checkbox(valuespec):
                    html.open_div(class_=[
                        "toggle_switch_container", modified_cls,
                        "on" if value else None
                    ])
                    html.toggle_switch(
                        enabled=value,
                        help_txt=_("Immediately toggle this setting"),
                        href=makeactionuri(request, transactions,
                                           [("_action", "toggle"),
                                            ("_varname", varname)]),
                        class_=modified_cls,
                        title=value_title,
                    )
                    html.close_div()

                else:
                    html.a(to_text,
                           href=edit_url,
                           class_=modified_cls,
                           title=value_title)

            if header_is_painted:
                forms.end()
        if not at_least_one_painted and search:
            html.show_message(
                _("Did not find any global setting matching your search."))
        html.close_div()