示例#1
0
def _validate_general_host_attributes(host_attributes, new):
    """Check if the given attribute name exists, no type check"""
    all_host_attribute_names = _retrieve_host_attributes()
    # inventory_failed and site are no "real" host_attributes (TODO: Clean this up!)
    all_host_attribute_names.extend(["inventory_failed", "site"])
    for name, value in host_attributes.items():
        if name not in all_host_attribute_names:
            raise MKUserError(
                None,
                _("Unknown attribute: %s") % escaping.escape_attribute(name))

        # For real host attributes validate the values
        try:
            attr = watolib.host_attribute(name)
        except KeyError:
            attr = None

        if attr is not None:
            if attr.needs_validation("host", new):
                attr.validate_input(value, "")

        # The site attribute gets an extra check
        if name == "site" and value not in allsites().keys():
            raise MKUserError(
                None,
                _("Unknown site %s") % escaping.escape_attribute(value))
示例#2
0
def _validate_general_host_attributes(host_attributes,
                                      extra_attrs: Sequence[str], new: bool):
    """Check if the given attribute name exists, no type check"""
    all_host_attribute_names = _retrieve_host_attributes()
    all_host_attribute_names.extend(extra_attrs)
    for name, value in host_attributes.items():
        if name not in all_host_attribute_names:
            raise MKUserError(
                None,
                _("Unknown attribute: %s") % escaping.escape_attribute(name))

        # For real host attributes validate the values
        try:
            attr: Optional[ABCHostAttribute] = host_attribute(name)
        except KeyError:
            attr = None

        if attr is not None:
            if attr.needs_validation("host", new):
                attr.validate_input(value, "")

        # The site attribute gets an extra check
        if name == "site" and value not in allsites().keys():
            raise MKUserError(
                None,
                _("Unknown site %s") % escaping.escape_attribute(value))
示例#3
0
def _validate_general_host_attributes(host_attributes, new):
    # inventory_failed and site are no "real" host_attributes (TODO: Clean this up!)
    all_host_attribute_names = list(
        host_attribute_registry.keys()) + ["inventory_failed", "site"]
    for name, value in host_attributes.items():
        if name not in all_host_attribute_names:
            raise MKUserError(
                None,
                _("Unknown attribute: %s") % escaping.escape_attribute(name))

        # For real host attributes validate the values
        try:
            attr: Optional[ABCHostAttribute] = watolib.host_attribute(name)
        except KeyError:
            attr = None

        if attr is not None:
            if attr.needs_validation("host", new):
                attr.validate_input(value, "")

        # The site attribute gets an extra check
        if name == "site" and value not in allsites().keys():
            raise MKUserError(
                None,
                _("Unknown site %s") % escaping.escape_attribute(value))
示例#4
0
def _render_attributes(**attrs: HTMLTagAttributeValue) -> Iterator[str]:
    css = _get_normalized_css_classes(attrs)
    if css:
        attrs["class"] = css

    # options such as 'selected' and 'checked' dont have a value in html tags
    options = []

    # Links require href to be first attribute
    href = attrs.pop('href', None)
    if href:
        attributes = list(attrs.items())
        attributes.insert(0, ("href", href))
    else:
        attributes = list(attrs.items())

    # render all attributes
    for key_unescaped, v in attributes:
        if v is None:
            continue

        key = escaping.escape_attribute(key_unescaped.rstrip('_'))

        if key.startswith('data_'):
            key = key.replace('_', '-', 1)  # HTML data attribute: 'data-name'

        if v == '':
            options.append(key)
            continue

        if not isinstance(v, list):
            v = escaping.escape_attribute(v)
        else:
            if key == "class":
                sep = ' '
            elif key == "style" or key.startswith('on'):
                sep = '; '
            else:
                # TODO: Can we drop this special Feature? No idea what it is used for.
                sep = '_'

            joined_value = sep.join(
                [a for a in (escaping.escape_attribute(vi) for vi in v) if a])

            # TODO: Can we drop this special feature? Find an cleanup the call sites
            if sep.startswith(';'):
                joined_value = re.sub(';+', ';', joined_value)

            v = joined_value

        yield ' %s=\"%s\"' % (key, v)

    for k in options:
        yield " %s=\'\'" % k
示例#5
0
def _get_api_call():
    action = request.var('action')
    for cls in api_call_collection_registry.values():
        api_call = cls().get_api_calls().get(action)
        if api_call:
            return api_call
    raise MKUserError(None, "Unknown API action %s" % escaping.escape_attribute(action))
示例#6
0
def _get_api_call() -> APICallDefinitionDict:
    action = request.get_str_input_mandatory("action")
    for cls in api_call_collection_registry.values():
        api_call = cls().get_api_calls().get(action)
        if api_call:
            return api_call
    raise MKUserError(None, "Unknown API action %s" % escaping.escape_attribute(action))
示例#7
0
def page_login() -> None:
    title = _("Checkmk Mobile")
    mobile_html_head(title)
    jqm_page_header(title, id_="login")
    html.div(_("Welcome to Checkmk Mobile."), id_="loginhead")

    html.begin_form("login", method='POST', add_transid=False)
    # Keep information about original target URL
    default_origtarget = "index.py" if requested_file_name(request) in ["login", "logout"
                                                                       ] else makeuri(request, [])
    origtarget = request.get_url_input("_origtarget", default_origtarget)
    html.hidden_field('_origtarget', escaping.escape_attribute(origtarget))

    html.text_input("_username", label=_("Username:"******"username", id_="input_user")
    html.password_input(
        "_password",
        size=None,
        label=_("Password:"******"current-password",
        id_="input_pass",
    )
    html.br()
    html.button("_login", _('Login'))
    html.set_focus("_username")
    html.end_form()
    html.open_div(id_="loginfoot")
    html.img("themes/facelift/images/logo_cmk_small.png", class_="logomk")
    html.div(HTML(_("&copy; <a target=\"_blank\" href=\"https://checkmk.com\">tribe29 GmbH</a>")),
             class_="copyright")
    html.close_div()  # close content-div
    html.close_div()
    html.close_div()  # close page-div
    mobile_html_foot()
示例#8
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_to_html(
                _("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()
        _changes.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())
示例#9
0
    def run(self) -> Iterator[ACResult]:
        self._executed = True
        try:
            # Do not merge results that have been gathered on one site for different sites
            results = list(self.execute())
            num_sites = len(set(r.site_id for r in results))
            if num_sites > 1:
                for result in results:
                    result.from_test(self)
                    yield result
                return

            # Merge multiple results produced for a single site
            total_result = ACResult.merge(*list(self.execute()))
            total_result.from_test(self)
            yield total_result
        except Exception:
            logger.exception("error executing configuration test %s",
                             self.__class__.__name__)
            result = ACResultCRIT(
                "<pre>%s</pre>" % _("Failed to execute the test %s: %s") %
                (escaping.escape_attribute(
                    self.__class__.__name__), traceback.format_exc()))
            result.from_test(self)
            yield result
示例#10
0
def time_series_math(
    operator_id: Literal["+", "*", "-", "/", "MAX", "MIN", "AVERAGE", "MERGE"],
    operands_evaluated: List[TimeSeries],
) -> Optional[TimeSeries]:
    operators = time_series_operators()
    if operator_id not in operators:
        raise MKGeneralException(
            _("Undefined operator '%s' in graph expression")
            % escaping.escape_attribute(operator_id)
        )
    # Test for correct arity on FOUND[evaluated] data
    if any(
        (
            operator_id in ["-", "/"] and len(operands_evaluated) != 2,
            len(operands_evaluated) < 1,
        )
    ):
        # raise MKGeneralException(_("Incorrect amount of data to correctly evaluate expression"))
        # Silently return so to get an empty graph slot
        return None

    _op_title, op_func = operators[operator_id]
    twindow = operands_evaluated[0].twindow

    return TimeSeries([op_func_wrapper(op_func, tsp) for tsp in zip(*operands_evaluated)], twindow)
示例#11
0
def _show_output_box(title, content):
    html.h3(title, class_="table")
    html.open_div(class_="log_output")
    html.write_html(
        HTML(escaping.escape_attribute(content).replace("\n", "<br>").replace(" ", "&nbsp;"))
    )
    html.close_div()
示例#12
0
def top_heading(
    writer: HTMLWriter,
    request: Request,
    title: str,
    breadcrumb: Breadcrumb,
    page_menu: Optional[PageMenu] = None,
    page_state: Optional[PageState] = None,
    *,
    browser_reload: float,
) -> None:
    writer.open_div(id_="top_heading")
    writer.open_div(class_="titlebar")

    # HTML() is needed here to prevent a double escape when we do  self._escape_attribute
    # here and self.a() escapes the content (with permissive escaping) again. We don't want
    # to handle "title" permissive.
    html_title = HTML(escaping.escape_attribute(title))
    writer.a(
        html_title,
        class_="title",
        href="#",
        onfocus="if (this.blur) this.blur();",
        onclick="this.innerHTML='%s'; document.location.reload();" %
        _("Reloading..."),
    )

    if breadcrumb:
        BreadcrumbRenderer().show(breadcrumb)

    if page_state is None:
        page_state = _make_default_page_state(
            writer,
            request,
            browser_reload=browser_reload,
        )

    if page_state:
        PageStateRenderer().show(page_state)

    writer.close_div()  # titlebar

    if page_menu:
        PageMenuRenderer().show(
            page_menu,
            hide_suggestions=not user.get_tree_state("suggestions", "all",
                                                     True),
        )

    writer.close_div()  # top_heading

    if page_menu:
        PageMenuPopupsRenderer().show(page_menu)

    if active_config.debug:
        _dump_get_vars(
            writer,
            request,
        )
示例#13
0
def format_plugin_output(output: str,
                         row: "Optional[Row]" = None,
                         shall_escape: bool = True) -> HTML:
    assert not isinstance(output, dict)
    ok_marker = '<b class="stmark state0">OK</b>'
    warn_marker = '<b class="stmark state1">WARN</b>'
    crit_marker = '<b class="stmark state2">CRIT</b>'
    unknown_marker = '<b class="stmark state3">UNKN</b>'

    # In case we have a host or service row use the optional custom attribute
    # ESCAPE_PLUGIN_OUTPUT (set by host / service ruleset) to override the global
    # setting.
    if row:
        custom_vars = row.get("service_custom_variables",
                              row.get("host_custom_variables", {}))
        if "ESCAPE_PLUGIN_OUTPUT" in custom_vars:
            shall_escape = custom_vars["ESCAPE_PLUGIN_OUTPUT"] == "1"

    if shall_escape:
        output = escaping.escape_attribute(output)
    else:
        output = "%s" % output

    output = (output.replace("(!)",
                             warn_marker).replace("(!!)", crit_marker).replace(
                                 "(?)",
                                 unknown_marker).replace("(.)", ok_marker))

    if row and "[running on" in output:
        a = output.index("[running on")
        e = output.index("]", a)
        hosts = output[a + 12:e].replace(" ", "").split(",")
        h = get_host_list_links(row["site"], hosts)
        output = output[:a] + "running on " + ", ".join(h) + output[e + 1:]

    prevent_url_icons = (row.get("service_check_command", "")
                         == "check_mk-checkmk_agent"
                         if row is not None else False)
    if shall_escape and not prevent_url_icons:
        http_url = r"(http[s]?://[A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+)"
        # (?:&lt;A HREF=&quot;), (?: target=&quot;_blank&quot;&gt;)? and endswith(" </A>") is a special
        # handling for the HTML code produced by check_http when "clickable URL" option is active.
        output = re.sub(
            "(?:&lt;A HREF=&quot;)?" + http_url +
            "(?: target=&quot;_blank&quot;&gt;)?",
            lambda p: str(
                html.render_icon_button(
                    unescape(p.group(1).replace("&quot;", "")),
                    unescape(p.group(1).replace("&quot;", "")),
                    "link",
                )),
            output,
        )

        if output.endswith(" &lt;/A&gt;"):
            output = output[:-11]

    return HTML(output)
示例#14
0
def _validate_host_tags(host_tags):
    for tag_group_id, tag_id in host_tags.items():
        for tag_group in config.tags.tag_groups:
            if tag_group.id == tag_group_id:
                for grouped_tag in tag_group.tags:
                    if grouped_tag.id == tag_id:
                        break
                else:
                    raise MKUserError(
                        None,
                        _("Unknown tag %s") %
                        escaping.escape_attribute(tag_id))
                break
        else:
            raise MKUserError(
                None,
                _("Unknown tag group %s") %
                escaping.escape_attribute(tag_group_id))
示例#15
0
def _show_output_box(title: str, content: bytes) -> None:
    html.h3(title, class_="table")
    html.open_div(class_="log_output")
    html.write_html(
        HTML(
            escaping.escape_attribute(
                content.decode(errors="surrogateescape")).replace(
                    "\n", "<br>").replace(" ", "&nbsp;")))
    html.close_div()
示例#16
0
def compute_output_message(effective_state, rule):
    output = []
    if effective_state["output"]:
        output.append(effective_state["output"])

    str_state = str(effective_state["state"])
    if str_state in rule.get("state_messages", {}):
        output.append(escaping.escape_attribute(rule["state_messages"][str_state]))
    return ", ".join(output)
示例#17
0
def _validate_host_tags(host_tags):
    """Check if the tag group exists and the tag value is valid"""
    for tag_group_id, tag_id in host_tags.items():
        for tag_group in active_config.tags.tag_groups:
            if tag_group.id == tag_group_id:
                for grouped_tag in tag_group.tags:
                    if grouped_tag.id == tag_id:
                        break
                else:
                    raise MKUserError(
                        None,
                        _("Unknown tag %s") %
                        escaping.escape_attribute(tag_id))
                break
        else:
            raise MKUserError(
                None,
                _("Unknown tag group %s") %
                escaping.escape_attribute(tag_group_id))
示例#18
0
def check_aggregation_title_uniqueness(aggregations):
    known_titles: Set[Any] = set()
    for attrs in aggregations.values():
        title = attrs["title"]
        if title in known_titles:
            raise MKConfigError(
                _('Duplicate BI aggregation with the title "<b>%s</b>". '
                  "Please check your BI configuration and make sure that within each group no aggregation has "
                  "the same title as any other. Note: you can use arguments in the top level "
                  "aggregation rule, like <tt>Host $HOST$</tt>.") %
                (escaping.escape_attribute(title)))
        known_titles.add(title)
示例#19
0
def check_title_uniqueness(forest):
    # Legacy, will be removed any decade from now
    # One aggregation cannot be in mutliple groups.
    known_titles: Set[Any] = set()
    for aggrs in forest.values():
        for aggr in aggrs:
            title = aggr["title"]
            if title in known_titles:
                raise MKConfigError(
                    _('Duplicate BI aggregation with the title "<b>%s</b>". '
                      "Please check your BI configuration and make sure that within each group no aggregation has "
                      "the same title as any other. Note: you can use arguments in the top level "
                      "aggregation rule, like <tt>Host $HOST$</tt>.") %
                    (escaping.escape_attribute(title)))
            known_titles.add(title)
示例#20
0
    def _from_vars(self) -> None:
        user.need_permission("wato.download_agent_output")

        host_name = request.var("host")
        if not host_name:
            raise MKGeneralException(_("The host is missing."))

        ty = request.var("type")
        if ty not in ["walk", "agent"]:
            raise MKGeneralException(_("Invalid type specified."))

        self._back_url = request.get_url_input("back_url", deflt="") or None

        host = watolib.Folder.current().host(host_name)
        if not host:
            raise MKGeneralException(
                _("Host is not managed by WATO. "
                  'Click <a href="%s">here</a> to go back.') %
                escape_attribute(self._back_url))
        host.need_permission("read")

        self._request = FetchAgentOutputRequest(host=host, agent_type=ty)
示例#21
0
 def render(self, row: Row, cell: Cell) -> CellSpec:
     return "", escaping.escape_attribute(row["aggr_name"])
示例#22
0
def _transform_builtin_dashboards() -> None:
    if 'builtin_dashboards_transformed' in g:
        return  # Only do this once
    for name, dashboard in builtin_dashboards.items():
        # Do not transform dashboards which are already in the new format
        if 'context' in dashboard:
            continue

        # Transform the dashlets
        for nr, dashlet in enumerate(dashboard['dashlets']):
            dashlet.setdefault('show_title', True)

            if dashlet.get('url', '').startswith('dashlet_hoststats') or \
                    dashlet.get('url', '').startswith('dashlet_servicestats'):

                # hoststats and servicestats
                dashlet['type'] = dashlet['url'][8:].split('.', 1)[0]

                if '?' in dashlet['url']:
                    # Transform old parameters:
                    # wato_folder
                    # host_contact_group
                    # service_contact_group
                    paramstr = dashlet['url'].split('?', 1)[1]
                    dashlet['context'] = {}
                    for key, val in [p.split('=', 1) for p in paramstr.split('&')]:
                        if key == 'host_contact_group':
                            dashlet['context']['opthost_contactgroup'] = {
                                'neg_opthost_contact_group': '',
                                'opthost_contact_group': val,
                            }
                        elif key == 'service_contact_group':
                            dashlet['context']['optservice_contactgroup'] = {
                                'neg_optservice_contact_group': '',
                                'optservice_contact_group': val,
                            }
                        elif key == 'wato_folder':
                            dashlet['context']['wato_folder'] = {
                                'wato_folder': val,
                            }

                del dashlet['url']

            elif dashlet.get('urlfunc') and not isinstance(dashlet['urlfunc'], str):
                raise MKGeneralException(
                    _('Unable to transform dashlet %d of dashboard %s: '
                      'the dashlet is using "urlfunc" which can not be '
                      'converted automatically.') % (nr, name))

            elif dashlet.get('url', '') != '' or dashlet.get('urlfunc') or dashlet.get('iframe'):
                # Normal URL based dashlet
                dashlet['type'] = 'url'

                if dashlet.get('iframe'):
                    dashlet['url'] = dashlet['iframe']
                    del dashlet['iframe']

            elif dashlet.get('view', '') != '':
                # Transform views
                # There might be more than the name in the view definition
                view_name = dashlet['view'].split('&')[0]

                # Copy the view definition into the dashlet
                copy_view_into_dashlet(dashlet, nr, view_name, load_from_all_views=True)
                del dashlet['view']

            else:
                raise MKGeneralException(
                    _('Unable to transform dashlet %d of dashboard %s. '
                      'You will need to migrate it on your own. Definition: %r') %
                    (nr, name, escaping.escape_attribute(dashlet)))

            dashlet.setdefault('context', {})
            dashlet.setdefault('single_infos', [])

        # the modification time of builtin dashboards can not be checked as on user specific
        # dashboards. Set it to 0 to disable the modification chech.
        dashboard.setdefault('mtime', 0)

        dashboard.setdefault('show_title', True)
        if dashboard['title'] is None:
            dashboard['title'] = _('No title')
            dashboard['show_title'] = False

        dashboard.setdefault('single_infos', [])
        dashboard.setdefault('context', {})
        dashboard.setdefault('topic', _('Overview'))
        dashboard.setdefault('description', dashboard.get('title', ''))
    g.builtin_dashboards_transformed = True
示例#23
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(
                makeactionuri(request, transactions, [
                    ("_do", "enable"),
                    ("_test_id", worst_result.test_id),
                ]),
                _("Reenable this test"),
                "enable_test",
            )
        else:
            html.icon_button(
                makeactionuri(request, transactions, [
                    ("_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(
                        makeactionuri(request, transactions, [
                            ("_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(
                        makeactionuri(request, transactions, [
                            ("_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_text("")

        # 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")
示例#24
0
def test_htmllib_integration():
    assert escaping.escape_attribute("") == ""
    assert escaping.escape_text("") == ""
示例#25
0
def test_escape_attribute(inp, out):
    assert escaping.escape_attribute(inp) == out
示例#26
0
def _transform_builtin_dashboards() -> None:
    for name, dashboard in builtin_dashboards.items():
        # Do not transform dashboards which are already in the new format
        if "context" in dashboard:
            continue

        # Transform the dashlets
        for nr, dashlet in enumerate(dashboard["dashlets"]):
            dashlet.setdefault("show_title", True)

            if dashlet.get("url", "").startswith("dashlet_hoststats") or dashlet.get(
                "url", ""
            ).startswith("dashlet_servicestats"):

                # hoststats and servicestats
                dashlet["type"] = dashlet["url"][8:].split(".", 1)[0]

                if "?" in dashlet["url"]:
                    # Transform old parameters:
                    # wato_folder
                    # host_contact_group
                    # service_contact_group
                    paramstr = dashlet["url"].split("?", 1)[1]
                    dashlet["context"] = {}
                    for key, val in [p.split("=", 1) for p in paramstr.split("&")]:
                        if key == "host_contact_group":
                            dashlet["context"]["opthost_contactgroup"] = {
                                "neg_opthost_contact_group": "",
                                "opthost_contact_group": val,
                            }
                        elif key == "service_contact_group":
                            dashlet["context"]["optservice_contactgroup"] = {
                                "neg_optservice_contact_group": "",
                                "optservice_contact_group": val,
                            }
                        elif key == "wato_folder":
                            dashlet["context"]["wato_folder"] = {
                                "wato_folder": val,
                            }

                del dashlet["url"]

            elif dashlet.get("urlfunc") and not isinstance(dashlet["urlfunc"], str):
                raise MKGeneralException(
                    _(
                        "Unable to transform dashlet %d of dashboard %s: "
                        'the dashlet is using "urlfunc" which can not be '
                        "converted automatically."
                    )
                    % (nr, name)
                )

            elif dashlet.get("url", "") != "" or dashlet.get("urlfunc") or dashlet.get("iframe"):
                # Normal URL based dashlet
                dashlet["type"] = "url"

                if dashlet.get("iframe"):
                    dashlet["url"] = dashlet["iframe"]
                    del dashlet["iframe"]

            elif dashlet.get("view", "") != "":
                # Transform views
                # There might be more than the name in the view definition
                view_name = dashlet["view"].split("&")[0]

                # Copy the view definition into the dashlet
                copy_view_into_dashlet(dashlet, nr, view_name, load_from_all_views=True)
                del dashlet["view"]

            else:
                raise MKGeneralException(
                    _(
                        "Unable to transform dashlet %d of dashboard %s. "
                        "You will need to migrate it on your own. Definition: %r"
                    )
                    % (nr, name, escaping.escape_attribute(dashlet))
                )

            dashlet.setdefault("context", {})
            dashlet.setdefault("single_infos", [])

        # the modification time of builtin dashboards can not be checked as on user specific
        # dashboards. Set it to 0 to disable the modification chech.
        dashboard.setdefault("mtime", 0)

        dashboard.setdefault("show_title", True)
        if dashboard["title"] is None:
            dashboard["title"] = _("No title")
            dashboard["show_title"] = False

        dashboard.setdefault("single_infos", [])
        dashboard.setdefault("context", {})
        dashboard.setdefault("topic", _("Overview"))
        dashboard.setdefault("description", dashboard.get("title", ""))