def page(self) -> AjaxPageResult: settings = json.loads(request.get_str_input_mandatory("settings")) try: dashlet_type = cast(Type[ABCFigureDashlet], dashlet_registry[settings.get("type")]) except KeyError: raise MKUserError("type", _("The requested element type does not exist.")) settings = dashlet_vs_general_settings( dashlet_type, dashlet_type.single_infos()).value_from_json(settings) raw_properties = request.get_str_input_mandatory("properties") properties = dashlet_type.vs_parameters().value_from_json( json.loads(raw_properties)) context = json.loads(request.get_str_input_mandatory("context", "{}")) # Inject the infos because the datagenerator is a separate instance to dashlet # TODO: Can we do better than using fake arguments below? We *really* need an instance, # because in general, infos() is an *instance* method, not a class method. settings["infos"] = dashlet_type(dashboard_name="", dashboard={ "context": {} }, dashlet_id=0, dashlet={ "context": {} }).infos() response_data = dashlet_type.generate_response_data( properties, context, settings) return create_figures_response(response_data)
def ajax_tree_openclose() -> None: tree = request.get_str_input_mandatory("tree") name = request.get_str_input_mandatory("name") user.set_tree_state(tree, name, request.get_str_input("state")) user.save_tree_states() response.set_data("OK") # Write out something to make debugging easier
def ajax_set_rowselection() -> None: ident = request.get_str_input_mandatory("id") action = request.get_str_input_mandatory("action", "set") if action not in ["add", "del", "set", "unset"]: raise MKUserError(None, _("Invalid action")) rows = request.get_str_input_mandatory("rows", "").split(",") user.set_rowselection(selection_id(), ident, rows, action)
def recover_pre_2_1_range_filter_request_vars( query: query_filters.NumberRangeQuery): """Some range filters used the _to suffix instead of the standard _until. Do inverse translation to search for this request vars.""" request_var_match = ((var, re.sub("_until(_|$)", "_to\\1", var)) for var in query.request_vars) return { current_var: (request.get_str_input_mandatory(current_var, "") or request.get_str_input_mandatory(old_var, "")) for current_var, old_var in request_var_match }
def page_graph_dashlet() -> None: spec = request.var("spec") if not spec: raise MKUserError("spec", _("Missing spec parameter")) graph_identification = json.loads(request.get_str_input_mandatory("spec")) render = request.var("render") if not render: raise MKUserError("render", _("Missing render parameter")) custom_graph_render_options = json.loads( request.get_str_input_mandatory("render")) host_service_graph_dashlet_cmk(graph_identification, custom_graph_render_options)
def show(self, view: "View", rows: Rows) -> None: csv_separator = request.get_str_input_mandatory("csv_separator", ";") first = True resp = [] for cell in view.group_cells + view.row_cells: if first: first = False else: resp.append(csv_separator) title = cell.export_title() resp.append('"%s"' % self._format_for_csv(title)) for row in rows: resp.append("\n") first = True for cell in view.group_cells + view.row_cells: if first: first = False else: resp.append(csv_separator) joined_row = join_row(row, cell) content = cell.render_for_export(joined_row) resp.append('"%s"' % self._format_for_csv(content)) response.set_data("".join(resp))
def page(self) -> PageResult: """Determines the hosts to be shown""" user.need_permission("general.parent_child_topology") topology_settings = TopologySettings() if request.var("filled_in"): # Parameters from the check_mk filters self._update_topology_settings_with_context(topology_settings) elif request.var("host_name"): # Explicit host_name. Used by icon linking to Topology topology_settings.growth_root_nodes = { HostName(html.request.get_str_input_mandatory("host_name")) } else: # Default page without further context topology_settings.growth_root_nodes = self._get_default_view_hostnames( topology_settings.growth_auto_max_nodes ) if request.has_var("topology_settings"): # These parameters are usually generated within javascript through user interactions try: settings_from_var = json.loads(request.get_str_input_mandatory("topology_settings")) for key, value in settings_from_var.items(): setattr(topology_settings, key, value) except (TypeError, ValueError): raise MKGeneralException(_("Invalid topology_settings %r") % topology_settings) self.show_topology(topology_settings)
def value(self) -> FilterHTTPVariables: """Returns the current representation of the filter settings from the HTML var context. This can be used to persist the filter settings.""" return { varname: request.get_str_input_mandatory(varname, "") for varname in self.htmlvars }
def page(self) -> AjaxPageResult: check_csrf_token() layout_var = request.get_str_input_mandatory("layout", "{}") layout_config = json.loads(layout_var) active_config.bi_layouts["templates"].update(layout_config) BILayoutManagement.save_layouts() return {}
def _ajax_tag_tree_enter(self): response.set_content_type("application/json") self._load() path = request.get_str_input_mandatory("path").split( "|") if request.var("path") else [] self._cwds[self._current_tree_id] = path self._save_user_settings() response.set_data("OK")
def _from_vars(self): self._hostname = self._vs_host().from_html_vars("host") self._vs_host().validate_value(self._hostname, "host") # TODO: validate all fields self._item = request.get_str_input_mandatory("file", "") self._match_txt = request.get_str_input_mandatory("match", "") self._host = Folder.current().host(self._hostname) if self._hostname and not self._host: raise MKUserError(None, _("This host does not exist.")) if self._item and not self._hostname: raise MKUserError( None, _("You need to specify a host name to test file matching."))
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))
def page_api() -> None: try: if not request.has_var("output_format"): response.set_content_type("application/json") output_format = "json" else: output_format = request.get_ascii_input_mandatory( "output_format", "json").lower() if output_format not in _FORMATTERS: response.set_content_type("text/plain") raise MKUserError( None, "Only %s are supported as output formats" % " and ".join('"%s"' % f for f in _FORMATTERS), ) # TODO: Add some kind of helper for boolean-valued variables? pretty_print = False pretty_print_var = request.get_str_input_mandatory( "pretty_print", "no").lower() if pretty_print_var not in ("yes", "no"): raise MKUserError(None, 'pretty_print must be "yes" or "no"') pretty_print = pretty_print_var == "yes" api_call = _get_api_call() _check_permissions(api_call) request_object = _get_request(api_call) _check_formats(output_format, api_call, request_object) _check_request_keys(api_call, request_object) resp = _execute_action(api_call, request_object) except MKAuthException as e: resp = { "result_code": 1, "result": _("Authorization Error. Insufficent permissions for '%s'") % e, } except MKException as e: resp = { "result_code": 1, "result": _("Checkmk exception: %s\n%s") % (e, "".join(traceback.format_exc())), } except Exception: if active_config.debug: raise logger.exception("error handling web API call") resp = { "result_code": 1, "result": _("Unhandled exception: %s") % traceback.format_exc(), } response.set_data( _FORMATTERS[output_format][1 if pretty_print else 0](resp))
def infos(self) -> SingleInfos: # Hack for create mode of dashlet editor. The user first selects a datasource and then the # single contexts, the dashlet editor needs to use these information. if requested_file_name(request) == "edit_dashlet" and request.has_var( "datasource"): ds_name = request.get_str_input_mandatory("datasource") return list(data_source_registry[ds_name]().infos) # TODO: Hmmm... return self._get_infos_from_view_spec(self._dashlet_spec)
def robotmk_report_page() -> cmk.gui.pages.PageResult: """Renders the content of the RobotMK html log file""" site_id, host_name, service_description = _get_mandatory_request_vars() report_type: str = request.get_str_input_mandatory("report_type") content = _get_html_from_livestatus(report_type, site_id, host_name, service_description) html_content = _get_cleaned_html_content(content[0].decode("utf-8")) html.write_html(html_content)
def page(self): # To prevent mixups in written files we use the same lock here as for # the normal WATO page processing. This might not be needed for some # special automation requests, like inventory e.g., but to keep it simple, # we request the lock in all cases. lock_config = not (self._command == "checkmk-automation" and request.get_str_input_mandatory("automation") == "active-check") with store.lock_checkmk_configuration( ) if lock_config else nullcontext(): self._execute_automation()
def page(self) -> AjaxPageResult: try: check_csrf_token() name = request.get_str_input_mandatory("name") url = makeuri_contextless(request, [("name", name)], "dashboard.py") validate_start_url(url, "") _set_user_attribute("start_url", repr(url)) except Exception: raise MKUserError(None, _("Failed to set start URL")) return {}
def ajax_save_treestate(): path_id = request.get_str_input_mandatory("path") current_ex_level_str, path = path_id.split(":", 1) current_ex_level = int(current_ex_level_str) if user.bi_expansion_level != current_ex_level: user.set_tree_states("bi", {}) user.set_tree_state("bi", path, request.var("state") == "open") user.save_tree_states() user.bi_expansion_level = current_ex_level
def ajax_snapin(): """Renders and returns the contents of the requested sidebar snapin(s) in JSON format""" response.set_content_type("application/json") user_config = UserSidebarConfig(user, active_config.sidebar) snapin_id = request.var("name") snapin_ids = ([snapin_id] if snapin_id else request.get_str_input_mandatory("names", "").split(",")) snapin_code: List[str] = [] for snapin_id in snapin_ids: try: snapin_instance = user_config.get_snapin(snapin_id).snapin_type() except KeyError: continue # Skip not existing snapins if not snapin_instance.may_see(): continue # When restart snapins are about to be refreshed, only render # them, when the core has been restarted after their initial # rendering if not snapin_instance.refresh_regularly( ) and snapin_instance.refresh_on_restart(): since = request.get_float_input_mandatory("since", 0) newest = since for site in sites.states().values(): prog_start = site.get("program_start", 0) if prog_start > newest: newest = prog_start if newest <= since: # no restart snapin_code.append("") continue with output_funnel.plugged(): try: snapin_instance.show() except Exception as e: write_snapin_exception(e) e_message = ( _("Exception during element refresh (element '%s')") % snapin_instance.type_name()) logger.error("%s %s: %s", request.requested_url, e_message, traceback.format_exc()) finally: snapin_code.append(output_funnel.drain()) response.set_data(json.dumps(snapin_code))
def _execute_cmk_automation(self): cmk_command = request.get_str_input_mandatory("automation") args = watolib_utils.mk_eval( request.get_str_input_mandatory("arguments")) indata = watolib_utils.mk_eval( request.get_str_input_mandatory("indata")) stdin_data = watolib_utils.mk_eval( request.get_str_input_mandatory("stdin_data")) timeout = watolib_utils.mk_eval( request.get_str_input_mandatory("timeout")) cmdline_cmd, serialized_result = check_mk_local_automation_serialized( command=cmk_command, args=args, indata=indata, stdin_data=stdin_data, timeout=timeout, ) # Don't use write_text() here (not needed, because no HTML document is rendered) response.set_data( self._format_cmk_automation_result( serialized_result=SerializedResult(serialized_result), cmk_command=cmk_command, cmdline_cmd=cmdline_cmd, ))
def selection_id() -> str: """Generates a selection id or uses the given one""" if not request.has_var("selection"): sel_id = utils.gen_id() request.set_var("selection", sel_id) return sel_id sel_id = request.get_str_input_mandatory("selection") # Avoid illegal file access by introducing .. or / if not re.match("^[-0-9a-zA-Z]+$", sel_id): new_id = utils.gen_id() request.set_var("selection", new_id) return new_id return sel_id
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("%s_groups" % self.type_name)) alias = request.get_str_input_mandatory("alias").strip() self.group = {"alias": alias} self._determine_additional_group_data() if self._new: self._name = request.get_ascii_input_mandatory("name").strip() groups.add_group(self._name, self.type_name, self.group) else: assert self._name is not None groups.edit_group(self._name, self.type_name, self.group) return redirect(mode_url("%s_groups" % self.type_name))
def _evaluate_user_opts(self) -> Tuple[TableRows, bool, Optional[str]]: assert self.id is not None table_id = self.id rows = self.rows search_term = None actions_enabled = self.options["searchable"] or self.options["sortable"] if not actions_enabled: return rows, False, None table_opts = user.tableoptions.setdefault(table_id, {}) # Handle the initial visibility of the actions actions_visible = table_opts.get("actions_visible", False) if request.get_ascii_input("_%s_actions" % table_id): actions_visible = request.get_ascii_input("_%s_actions" % table_id) == "1" table_opts["actions_visible"] = actions_visible if self.options["searchable"]: search_term = request.get_str_input_mandatory("search", "") # Search is always lower case -> case insensitive search_term = search_term.lower() if search_term: request.set_var("search", search_term) rows = _filter_rows(rows, search_term) if request.get_ascii_input("_%s_reset_sorting" % table_id): request.del_var("_%s_sort" % table_id) if "sort" in table_opts: del table_opts["sort"] # persist if self.options["sortable"]: # Now apply eventual sorting settings sort = self._get_sort_column(table_opts) if sort is not None: request.set_var("_%s_sort" % table_id, sort) table_opts["sort"] = sort # persist sort_col, sort_reverse = map(int, sort.split(",", 1)) rows = _sort_rows(rows, sort_col, sort_reverse) if actions_enabled: user.save_tableoptions() return rows, actions_visible, search_term
def ajax_render_tree(): aggr_group = request.get_str_input("group") aggr_title = request.get_str_input("title") omit_root = bool(request.var("omit_root")) only_problems = bool(request.var("only_problems")) rows = [] bi_manager = BIManager() bi_manager.status_fetcher.set_assumed_states(user.bi_assumptions) aggregation_id = request.get_str_input_mandatory("aggregation_id") bi_aggregation_filter = BIAggregationFilter( [], [], [aggregation_id], [aggr_title] if aggr_title is not None else [], [aggr_group] if aggr_group is not None else [], [], ) rows = bi_manager.computer.compute_legacy_result_for_filter( bi_aggregation_filter) # TODO: Cleanup the renderer to use a class registry for lookup renderer_class_name = request.var("renderer") if renderer_class_name == "FoldableTreeRendererTree": renderer_cls: Type[ABCFoldableTreeRenderer] = FoldableTreeRendererTree elif renderer_class_name == "FoldableTreeRendererBoxes": renderer_cls = FoldableTreeRendererBoxes elif renderer_class_name == "FoldableTreeRendererBottomUp": renderer_cls = FoldableTreeRendererBottomUp elif renderer_class_name == "FoldableTreeRendererTopDown": renderer_cls = FoldableTreeRendererTopDown else: raise NotImplementedError() renderer = renderer_cls( rows[0], omit_root=omit_root, expansion_level=user.bi_expansion_level, only_problems=only_problems, lazy=False, ) html.write_html(renderer.render())
def robotmk_download_page() -> cmk.gui.pages.PageResult: user.need_permission("general.see_crash_reports") site_id, host_name, service_description = _get_mandatory_request_vars() report_type: str = request.get_str_input_mandatory("report_type") filename = "Robot_Framework_log_%s_%s_%s_%s.tar.gz" % ( urlencode(site_id), urlencode(host_name), urlencode(service_description), time.strftime("%Y-%m-%d_%H-%M-%S"), ) response.headers[ "Content-Disposition"] = "Attachment; filename=%s" % filename response.headers["Content-Type"] = "application/x-tar" html_content: bytes = _get_html_from_livestatus(report_type, site_id, host_name, service_description)[0] response.set_data(_pack_html_content(report_type, html_content))
def _from_vars(self): self._start = bool(request.var("_start")) # 'all' not set -> only scan checked hosts in current folder, no recursion # otherwise: all host in this folder, maybe recursively self._all = bool(request.var("all")) self._complete_folder = self._all # Ignored during initial form display self._settings = ParentScanSettings( where=request.get_ascii_input_mandatory("where", "subfolder"), alias=request.get_str_input_mandatory("alias", "").strip(), recurse=html.get_checkbox("recurse") or False, select=request.get_ascii_input_mandatory("select", "noexplicit"), timeout=request.get_integer_input_mandatory("timeout", 8), probes=request.get_integer_input_mandatory("probes", 2), max_ttl=request.get_integer_input_mandatory("max_ttl", 10), force_explicit=html.get_checkbox("force_explicit") or False, ping_probes=request.get_integer_input_mandatory("ping_probes", 5), ) self._job = ParentScanBackgroundJob()
def _report_type(self) -> str: return request.get_str_input_mandatory("report_type")
def _get_mandatory_request_vars() -> Tuple[SiteId, HostName, str]: site_id: SiteId = SiteId(request.get_str_input_mandatory("site")) host_name: HostName = request.get_str_input_mandatory("host") service_description: str = request.get_str_input_mandatory("service") return site_id, host_name, service_description
def action(self) -> ActionResult: if html.form_submitted("search"): return None alias = request.get_str_input_mandatory("alias") unique, info = groups.is_alias_used("roles", self._role_id, alias) if not unique: assert info is not None raise MKUserError("alias", info) new_id = request.get_ascii_input_mandatory("id") if not new_id: raise MKUserError("id", "You have to provide a ID.") if not re.match("^[-a-z0-9A-Z_]*$", new_id): raise MKUserError( "id", _("Invalid role ID. Only the characters a-z, A-Z, 0-9, _ and - are allowed.") ) if new_id != self._role_id: if new_id in self._roles: raise MKUserError("id", _("The ID is already used by another role")) self._role["alias"] = alias # based on if not self._role.get("builtin"): basedon = request.get_ascii_input_mandatory("basedon") if basedon not in builtin_role_ids: raise MKUserError( "basedon", _("Invalid valid for based on. Must be id of builtin rule.") ) self._role["basedon"] = basedon # Permissions permissions = self._role["permissions"] for var_name, value in request.itervars(prefix="perm_"): try: perm = permission_registry[var_name[5:]] except KeyError: continue if value == "yes": permissions[perm.name] = True elif value == "no": permissions[perm.name] = False elif value == "default": try: del permissions[perm.name] except KeyError: pass # Already at defaults if self._role_id != new_id: self._roles[new_id] = self._role del self._roles[self._role_id] self._rename_user_role(self._role_id, new_id) self._save_roles() _changes.add_change( "edit-roles", _("Modified user role '%s'") % new_id, sites=get_login_sites() ) return redirect(mode_url("roles"))
def _end(self) -> None: if not self.rows and self.options["omit_if_empty"]: return if self.options["output_format"] == "csv": self._write_csv(csv_separator=request.get_str_input_mandatory( "csv_separator", ";")) return container: ContextManager[bool] = nullcontext(False) if self.title: if self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.open_div(class_="foldable_wrapper") container = foldable_container( treename="table", id_=self.id, isopen=self.isopen, indent=False, title=HTMLWriter.render_h3(self.title, class_=["treeangle", "title"]), save_state=self.options["foldable"] == Foldable.FOLDABLE_SAVE_STATE, ) else: html.h3(self.title, class_="table") with container: if self.help: html.help(self.help) if not self.rows: html.div(self.empty_text, class_="info") return # Controls whether or not actions are available for a table rows, actions_visible, search_term = self._evaluate_user_opts() # Apply limit after search / sorting etc. num_rows_unlimited = len(rows) limit = self.limit if limit: # only use rows up to the limit plus the fixed rows limited_rows = [] for index in range(num_rows_unlimited): row = rows[index] if index < limit or isinstance(row, GroupHeader) or row.fixed: limited_rows.append(row) # Display corrected number of rows num_rows_unlimited -= len([ r for r in limited_rows if isinstance(row, GroupHeader) or r.fixed ]) rows = limited_rows # Render header if self.limit_hint is not None: num_rows_unlimited = self.limit_hint if limit and num_rows_unlimited > limit: html.show_message( _("This table is limited to show only %d of %d rows. " 'Click <a href="%s">here</a> to disable the limitation.') % (limit, num_rows_unlimited, makeuri(request, [("limit", "none")]))) self._write_table(rows, num_rows_unlimited, self._show_action_row(), actions_visible, search_term) if self.title and self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.close_div() return