def action(self) -> ActionResult: if not transactions.check_transaction(): return None test_id = request.var("_test_id") site_id = request.var("_site_id") status_id = request.get_integer_input_mandatory("_status_id", 0) if not test_id: raise MKUserError("_ack_test_id", _("Needed variable missing")) if request.var("_do") in ["ack", "unack"]: if not site_id: raise MKUserError("_ack_site_id", _("Needed variable missing")) if site_id not in activation_sites(): raise MKUserError("_ack_site_id", _("Invalid site given")) if request.var("_do") == "ack": self._acknowledge_test(test_id, site_id, status_id) elif request.var("_do") == "unack": self._unacknowledge_test(test_id, site_id, status_id) elif request.var("_do") == "disable": self._disable_test(test_id) elif request.var("_do") == "enable": self._enable_test(test_id) else: raise NotImplementedError() return None
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())
def action(self) -> ActionResult: delname = request.var("_delete") if not delname: return redirect(mode_url("timeperiods")) if not transactions.check_transaction(): return redirect(mode_url("timeperiods")) if delname in watolib.timeperiods.builtin_timeperiods(): raise MKUserError("_delete", _("Builtin timeperiods can not be modified")) usages = self._find_usages_of_timeperiod(delname) if usages: message = "<b>%s</b><br>%s:<ul>" % ( _("You cannot delete this timeperiod."), _("It is still in use by"), ) for title, link in usages: message += '<li><a href="%s">%s</a></li>\n' % (link, title) message += "</ul>" raise MKUserError(None, message) del self._timeperiods[delname] watolib.timeperiods.save_timeperiods(self._timeperiods) _changes.add_change("edit-timeperiods", _("Deleted timeperiod %s") % delname) return redirect(mode_url("timeperiods"))
def action(self) -> ActionResult: varname = request.var("_varname") if not varname: return None action = request.var("_action") config_variable = config_variable_registry[varname]() def_value = self._default_values[varname] if not transactions.check_transaction(): return None if varname in self._current_settings: self._current_settings[ varname] = not self._current_settings[varname] else: self._current_settings[varname] = not def_value msg = _("Changed Configuration variable %s to %s.") % ( varname, "on" if self._current_settings[varname] else "off", ) save_global_settings(self._current_settings) _changes.add_change( "edit-configvar", msg, domains=[config_variable.domain()], need_restart=config_variable.need_restart(), ) if action == "_reset": flash(msg) return redirect(mode_url("globalvars"))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("tags")) vs = self._valuespec() aux_tag_spec = vs.from_html_vars("aux_tag") vs.validate_value(aux_tag_spec, "aux_tag") self._aux_tag = cmk.utils.tags.AuxTag.from_config(aux_tag_spec) self._aux_tag.validate() changed_hosttags_config = cmk.utils.tags.TagConfig.from_config( self._tag_config_file.load_for_reading()) if self._new: changed_hosttags_config.aux_tag_list.append(self._aux_tag) else: changed_hosttags_config.aux_tag_list.update( self._id, self._aux_tag) try: changed_hosttags_config.validate_config() except MKGeneralException as e: raise MKUserError(None, "%s" % e) self._tag_config_file.save(changed_hosttags_config.get_dict_format()) return redirect(mode_url("tags"))
def page_message(): if not user.may("general.message"): raise MKAuthException(_("You are not allowed to use the message module.")) title = _("Send user message") breadcrumb = make_simple_page_breadcrumb(mega_menu_registry.menu_setup(), title) menu = _page_menu(breadcrumb) html.header(title, breadcrumb, menu) vs_message = _vs_message() if transactions.check_transaction(): try: msg = vs_message.from_html_vars("_message") vs_message.validate_value(msg, "_message") _process_message_message(msg) except MKUserError as e: html.user_error(e) html.begin_form("message", method="POST") vs_message.render_input_as_form("_message", {}) html.hidden_fields() html.end_form() html.footer()
def action(self) -> ActionResult: try: transactions.check_transaction() user.save_file("parentscan", dict(self._settings._asdict())) self._job.set_function(self._job.do_execute, self._settings, self._get_tasks()) self._job.start() except Exception as e: if active_config.debug: raise logger.exception("Failed to start parent scan") raise MKUserError( None, _("Failed to start parent scan: %s") % ("%s" % e).replace("\n", "\n<br>") ) raise HTTPRedirect(self._job.detail_url())
def action(self) -> ActionResult: if not transactions.check_transaction(): return None vs = self._valuespec() self._connection_cfg = vs.from_html_vars("connection") vs.validate_value(self._connection_cfg, "connection") self._connection_cfg["type"] = "ldap" if self._new: self._connections.insert(0, self._connection_cfg) self._connection_id = self._connection_cfg["id"] else: self._connection_cfg["id"] = self._connection_id self._connections[self._connection_nr] = self._connection_cfg assert self._connection_id is not None if self._new: log_what = "new-ldap-connection" log_text = _("Created new LDAP connection") else: log_what = "edit-ldap-connection" log_text = _("Changed LDAP connection %s") % self._connection_id self._add_change(log_what, log_text) save_connection_config(self._connections) active_config.user_connections = ( self._connections) # make directly available on current page if request.var("_save"): return redirect(mode_url("ldap_config")) # Handle the case where a user hit "Save & Test" during creation return redirect(self.mode_url(_test="1", id=self._connection_id))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(self.mode_url()) connections = load_connection_config(lock=True) if request.has_var("_delete"): index = request.get_integer_input_mandatory("_delete") connection = connections[index] self._add_change( "delete-ldap-connection", _("Deleted LDAP connection %s") % (connection["id"])) del connections[index] save_connection_config(connections) elif request.has_var("_move"): from_pos = request.get_integer_input_mandatory("_move") to_pos = request.get_integer_input_mandatory("_index") connection = connections[from_pos] self._add_change( "move-ldap-connection", _("Changed position of LDAP connection %s to %d") % (connection["id"], to_pos), ) del connections[from_pos] # make to_pos now match! connections[to_pos:to_pos] = [connection] save_connection_config(connections) return redirect(self.mode_url())
def action(self) -> ActionResult: if transactions.check_transaction(): value = self._vs_key().from_html_vars("key") request.del_var("key_p_passphrase") self._vs_key().validate_value(value, "key") key_file = self._get_uploaded(value["key_file"]) if not key_file: raise MKUserError(None, _("You need to provide a key file.")) if ( not key_file.startswith("-----BEGIN ENCRYPTED PRIVATE KEY-----\n") or "-----END ENCRYPTED PRIVATE KEY-----\n" not in key_file or "-----BEGIN CERTIFICATE-----\n" not in key_file or not key_file.endswith("-----END CERTIFICATE-----\n") ): raise MKUserError(None, _("The file does not look like a valid key file.")) self._upload_key(key_file, value["alias"], value["passphrase"]) # FIXME: This leads to a circular import otherwise. This module (cmk.gui.key_mgmt) is # clearly outside of either cmk.gui.plugins.wato and cmk.gui.cee.plugins.wato so this # is obviously a very simple module-layer violation. This whole module should either # * be moved into cmk.gui.cee.plugins.wato # * or cmk.gui.cee.plugins.wato.module_registry should be moved up # Either way, this is outside my scope right now and shall be fixed. from cmk.gui.plugins.wato.utils.base_modes import mode_url return HTTPRedirect(mode_url(self.back_mode), code=302) return None
def handle_acknowledgement(): if not transactions.check_transaction(): return if request.var("_werk_ack"): werk_id = request.get_integer_input_mandatory("_werk_ack") if werk_id not in g_werks: raise MKUserError("werk", _("This werk does not exist.")) werk = g_werks[werk_id] if werk["compatible"] == "incomp_unack": acknowledge_werk(werk) html.show_message( _("Werk %s - %s has been acknowledged.") % (render_werk_id(werk, with_link=True), render_werk_title(werk)) ) load_werks() # reload ack states after modification render_unacknowleged_werks() elif request.var("_ack_all"): num = len(unacknowledged_incompatible_werks()) acknowledge_all_werks() flash(_("%d incompatible Werks have been acknowledged.") % num) load_werks() # reload ack states after modification html.reload_whole_page()
def action(self) -> ActionResult: if transactions.check_transaction(): keys = self.load() try: key_id_str = request.var("key") if key_id_str is None: raise Exception( "cannot happen") # is this really the case? key_id = int(key_id_str) except ValueError: raise MKUserError(None, _("You need to provide a valid key id.")) if key_id not in keys: raise MKUserError(None, _("You need to provide a valid key id.")) private_key = keys[key_id]["private_key"] value = self._vs_key().from_html_vars("key") self._vs_key().validate_value(value, "key") decrypt_private_key(private_key, value["passphrase"]) self._send_download(keys, key_id) return FinalizeRequest(code=200) return None
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("tags")) vs = self._valuespec() tag_group_spec = vs.from_html_vars("tag_group") vs.validate_value(tag_group_spec, "tag_group") # Create new object with existing host tags changed_hosttags_config = cmk.utils.tags.TagConfig.from_config( self._tag_config_file.load_for_modification()) changed_tag_group = cmk.utils.tags.TagGroup.from_config(tag_group_spec) self._tag_group = changed_tag_group if self._new: # Inserts and verifies changed tag group changed_hosttags_config.insert_tag_group(changed_tag_group) try: changed_hosttags_config.validate_config() except MKGeneralException as e: raise MKUserError(None, "%s" % e) self._save_tags_and_update_hosts( changed_hosttags_config.get_dict_format()) _changes.add_change( "edit-hosttags", _("Created new host tag group '%s'") % changed_tag_group.id) flash( _("Created new host tag group '%s'") % changed_tag_group.title) return redirect(mode_url("tags")) # Updates and verifies changed tag group changed_hosttags_config.update_tag_group(changed_tag_group) try: changed_hosttags_config.validate_config() except MKGeneralException as e: raise MKUserError(None, "%s" % e) remove_tag_ids, replace_tag_ids = identify_modified_tags( changed_tag_group, self._untainted_tag_group) tg_id = self._tag_group.id if tg_id is None: raise Exception("tag group ID not set") operation = OperationReplaceGroupedTags(tg_id, remove_tag_ids, replace_tag_ids) # Now check, if any folders, hosts or rules are affected message = _rename_tags_after_confirmation(self.breadcrumb(), operation) if message is False: return FinalizeRequest(code=200) self._save_tags_and_update_hosts( changed_hosttags_config.get_dict_format()) _changes.add_change( "edit-hosttags", _("Edited host tag group %s (%s)") % (message, self._id)) if isinstance(message, str): flash(message) return redirect(mode_url("tags"))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(self.mode_url()) if request.var("_delete"): delid = request.get_ascii_input_mandatory("_delete") if delid not in self._roles: raise MKUserError(None, _("This role does not exist.")) if transactions.transaction_valid() and self._roles[delid].get("builtin"): raise MKUserError(None, _("You cannot delete the builtin roles!")) users = userdb.load_users() for user in users.values(): if delid in user["roles"]: raise MKUserError( None, _("You cannot delete roles, that are still in use (%s)!") % delid, ) self._rename_user_role(delid, None) # Remove from existing users del self._roles[delid] self._save_roles() _changes.add_change( "edit-roles", _("Deleted role '%s'") % delid, sites=get_login_sites() ) elif request.var("_clone"): cloneid = request.get_ascii_input_mandatory("_clone") try: cloned_role = self._roles[cloneid] except KeyError: raise MKUserError(None, _("This role does not exist.")) newid = cloneid while newid in self._roles: newid += "x" new_role = {} new_role.update(cloned_role) new_alias = new_role["alias"] while not groups.is_alias_used("roles", newid, new_alias)[0]: new_alias += _(" (copy)") new_role["alias"] = new_alias if cloned_role.get("builtin"): new_role["builtin"] = False new_role["basedon"] = cloneid self._roles[newid] = new_role self._save_roles() _changes.add_change( "edit-roles", _("Created new role '%s'") % newid, sites=get_login_sites() ) return redirect(self.mode_url())
def action(self) -> ActionResult: if request.var("_action") != "discard": return None if not transactions.check_transaction(): return None if not self._may_discard_changes(): return None if not self.has_changes(): return None # Now remove all currently pending changes by simply restoring the last automatically # taken snapshot. Then activate the configuration. This should revert all pending changes. file_to_restore = self._get_last_wato_snapshot_file() if not file_to_restore: raise MKUserError(None, _("There is no WATO snapshot to be restored.")) msg = _("Discarded pending changes (Restored %s)") % file_to_restore # All sites and domains can be affected by a restore: Better restart everything. _changes.add_change( "changes-discarded", msg, domains=ABCConfigDomain.enabled_domains(), need_restart=True, ) self._extract_snapshot(file_to_restore) activate_changes.execute_activate_changes([ d.get_domain_request([]) for d in ABCConfigDomain.enabled_domains() ]) for site_id in activation_sites(): self.confirm_site_changes(site_id) build_index_background() make_header( html, self.title(), breadcrumb=self.breadcrumb(), show_body_start=display_options.enabled(display_options.H), show_top_heading=display_options.enabled(display_options.T), ) html.open_div(class_="wato") html.show_message(_("Successfully discarded all pending changes.")) html.javascript("hide_changes_buttons();") html.footer() return FinalizeRequest(code=200)
def confirm_with_preview(msg: Union[str, HTML], confirm_options: List[Tuple[str, str]], method: str = "POST") -> Optional[bool]: """Show a confirm dialog to the user BE AWARE: In case you just want to have some action confirmed by the user, you should use the javascript powere confirm dialg (make_confirm, add_confirm_on_submit, ...). This method is used only in places where we explicitly need to show important information to the user before he can decide whether or not to confirm the action. The confirm dialog is normally not a dialog which need to be protected by a transid itselfs. It is only a intermediate step to the real action But there are use cases where the confirm dialog is used during rendering a normal page, for example when deleting a dashlet from a dashboard. In such cases, the transid must be added by the confirm dialog. """ if request.var("_do_actions") == _("Cancel"): # User has pressed "Cancel", now invalidate the unused transid transactions.check_transaction() return None # None --> "Cancel" if not any( request.has_var(varname) for _title, varname in confirm_options): mobile = is_mobile(request, response) if mobile: html.open_center() html.open_div(class_="really") html.write_text(msg) html.begin_form("confirm", method=method, add_transid=False) html.hidden_fields(add_action_vars=True) for title, varname in confirm_options: html.button(varname, title, "really") html.button("_do_actions", _("Cancel")) html.end_form() html.close_div() if mobile: html.close_center() return False # False --> "Dialog shown, no answer yet" # Now check the transaction. True: "Yes", None --> Browser reload of "yes" page return True if transactions.check_transaction() else None
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("folder", folder=Folder.current().path())) count = request.get_integer_input_mandatory("count") folders = request.get_integer_input_mandatory("folders") levels = request.get_integer_input_mandatory("levels") created = self._create_random_hosts(Folder.current(), count, folders, levels) flash(_("Added %d random hosts.") % created) return redirect(mode_url("folder", folder=Folder.current().path()))
def action(self) -> ActionResult: if not transactions.check_transaction(): return None if self._job.is_active() or self._diagnostics_parameters is None: return redirect(self._job.detail_url()) self._job.set_function(self._job.do_execute, self._diagnostics_parameters) self._job.start() return redirect(self._job.detail_url())
def action(self) -> ActionResult: folder = Folder.current() if not transactions.check_transaction(): return redirect(mode_url("folder", folder=folder.path())) if request.var("_update_dns_cache") and self._should_use_dns_cache(): user.need_permission("wato.update_dns_cache") update_dns_cache_result = update_dns_cache(self._host.site_id()) infotext = (_("Successfully updated IP addresses of %d hosts.") % update_dns_cache_result.n_updated) if update_dns_cache_result.failed_hosts: infotext += "<br><br><b>Hostnames failed to lookup:</b> " + ", ".join( [ "<tt>%s</tt>" % h for h in update_dns_cache_result.failed_hosts ]) flash(infotext) return None if request.var("delete"): # Delete this host folder.delete_hosts([self._host.name()], automation=delete_hosts) return redirect(mode_url("folder", folder=folder.path())) if request.var("_remove_tls_registration"): remove_tls_registration( {self._host.site_id(): [self._host.name()]}) return None attributes = collect_attributes( "host" if not self._is_cluster() else "cluster", new=False) host = Host.host(self._host.name()) if host is None: flash(f"Host {self._host.name()} could not be found.") return None host.edit(attributes, self._get_cluster_nodes()) self._host = folder.load_host(self._host.name()) if request.var("_save"): return redirect( mode_url("inventory", folder=folder.path(), host=self._host.name())) if request.var("diag_host"): return redirect( mode_url("diag_host", folder=folder.path(), host=self._host.name(), _start_on_load="1")) return redirect(mode_url("folder", folder=folder.path()))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("tags")) if request.has_var("_delete"): return self._delete_tag_group() if request.has_var("_del_aux"): return self._delete_aux_tag() if request.var("_move"): return self._move_tag_group() return redirect(mode_url("tags"))
def show_create_view_dialog(next_url=None): vs_ds = DatasourceSelection() ds = "services" # Default selection title = _("Create view") breadcrumb = visuals.visual_page_breadcrumb("views", title, "create") make_header( html, title, breadcrumb, make_simple_form_page_menu( _("View"), breadcrumb, form_name="create_view", button_name="_save", save_title=_("Continue"), ), ) if request.var("_save") and transactions.check_transaction(): try: ds = vs_ds.from_html_vars("ds") vs_ds.validate_value(ds, "ds") if not next_url: next_url = makeuri( request, [("datasource", ds)], filename="create_view_infos.py", ) else: next_url = next_url + "&datasource=%s" % ds raise HTTPRedirect(next_url) except MKUserError as e: html.user_error(e) html.begin_form("create_view") html.hidden_field("mode", "create") forms.header(_("Select Datasource")) forms.section(vs_ds.title()) vs_ds.render_input("ds", ds) html.help(vs_ds.help()) forms.end() html.hidden_fields() html.end_form() html.footer()
def action(self) -> ActionResult: user.need_permission("wato.services") try: transactions.check_transaction() start_bulk_discovery( self._job, self._get_hosts_to_discover(), self._mode, self._do_full_scan, self._ignore_errors, self._bulk_size, ) except Exception as e: if active_config.debug: raise logger.exception("Failed to start bulk discovery") raise MKUserError( None, _("Failed to start discovery: %s") % ("%s" % e).replace("\n", "\n<br>")) raise HTTPRedirect(self._job.detail_url())
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(self.mode_url()) if not request.var("_delete"): return redirect(self.mode_url()) delname = request.var("_delete") for index, attr in enumerate(self._attrs): if attr["name"] == delname: self._attrs.pop(index) save_custom_attrs_to_mk_file(self._all_attrs) self._update_config() _changes.add_change("edit-%sattrs" % self._type, _("Deleted attribute %s") % (delname)) return redirect(self.mode_url())
def page(self) -> None: title = self._page_title() breadcrumb = self._breadcrumb() html.header(title, breadcrumb, self._page_menu(breadcrumb)) if transactions.check_transaction(): try: self._action() except MKUserError as e: user_errors.add(e) for message in get_flashed_messages(): html.show_message(message) html.show_user_errors() self._show_form()
def action(self) -> ActionResult: if not transactions.check_transaction(): return None user.need_permission("wato.edit_hosts") changed_attributes = collect_attributes("bulk", new=False) host_names = get_hostnames_from_checkboxes() for host_name in host_names: host = Folder.current().load_host(host_name) host.update_attributes(changed_attributes) # call_hook_hosts_changed() is called too often. # Either offer API in class Host for bulk change or # delay saving until end somehow flash(_("Edited %d hosts") % len(host_names)) return redirect(Folder.current().url())
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 action(self) -> ActionResult: if not transactions.check_transaction(): return None if request.var("_save"): try: self._validate_diag_html_vars() except MKUserError as e: user_errors.add(e) return None if request.var("go_to_properties"): # Save the ipaddress and/or community vs_host = self._vs_host() new = vs_host.from_html_vars("vs_host") vs_host.validate_value(new, "vs_host") # If both snmp types have credentials set - snmpv3 takes precedence return_message = [] if "ipaddress" in new: return_message.append(_("IP address")) if "snmp_v3_credentials" in new: if "snmp_community" in new: return_message.append(_("SNMPv3 credentials (SNMPv2 community was discarded)")) else: return_message.append(_("SNMPv3 credentials")) new["snmp_community"] = new["snmp_v3_credentials"] elif "snmp_community" in new: return_message.append(_("SNMP credentials")) # The hostname field used by this dialog is not a host_attribute. Remove it here to # prevent data corruption. new = new.copy() del new["hostname"] self._host.update_attributes(new) flash(_("Updated attributes: ") + ", ".join(return_message)) return redirect( mode_url( "edit_host", host=self._hostname, folder=Folder.current().path(), ) ) return None
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(self.mode_url()) if request.has_var("_delete"): icon_name = request.var("_delete") if icon_name in self._load_custom_icons(): os.remove( "%s/local/share/check_mk/web/htdocs/images/icons/%s.png" % (cmk.utils.paths.omd_root, icon_name)) elif request.has_var("_save"): vs_upload = self._vs_upload() icon_info = vs_upload.from_html_vars("_upload_icon") vs_upload.validate_value(icon_info, "_upload_icon") self._upload_icon(icon_info) return redirect(self.mode_url())
def page(self) -> None: row = self._get_crash_row() crash_info = self._get_crash_info(row) title = _("Crash report: %s") % self._crash_id breadcrumb = self._breadcrumb(title) html.header(title, breadcrumb, self._page_menu(breadcrumb, crash_info)) # Do not reveal crash context information to unauthenticated users or not permitted # users to prevent disclosure of internal information if not user.may("general.see_crash_reports"): html.show_error("<b>%s:</b> %s" % (_("Internal error"), crash_info["exc_value"])) html.p( _( "An internal error occurred while processing your request. " "You can report this issue to your Checkmk administrator. " "Detailed information can be found on the crash report page " "or in <tt>var/log/web.log</tt>." ) ) html.footer() return if request.has_var("_report") and transactions.check_transaction(): details = self._handle_report_form(crash_info) else: details = ReportSubmitDetails(name="", mail="") if crash_info["crash_type"] == "gui": html.show_error("<b>%s:</b> %s" % (_("Internal error"), crash_info["exc_value"])) html.p( _( "An internal error occured while processing your request. " "You can report this issue to the Checkmk team to help " "fixing this issue. Please use the form below for reporting." ) ) self._warn_about_local_files(crash_info) self._show_report_form(crash_info, details) self._show_crash_report(crash_info) self._show_crash_report_details(crash_info, row) html.footer()
def action(self) -> ActionResult: if transactions.check_transaction(): value = self._vs_key().from_html_vars("key") # Remove the secret key from known URL vars. Otherwise later constructed URLs # which use the current page context will contain the passphrase which could # leak the secret information request.del_var("key_p_passphrase") self._vs_key().validate_value(value, "key") self._create_key(value["alias"], value["passphrase"]) # FIXME: This leads to a circular import otherwise. This module (cmk.gui.key_mgmt) is # clearly outside of either cmk.gui.plugins.wato and cmk.gui.cee.plugins.wato so this # is obviously a very simple module-layer violation. This whole module should either # * be moved into cmk.gui.cee.plugins.wato # * or cmk.gui.cee.plugins.wato.module_registry should be moved up # Either way, this is outside my scope right now and shall be fixed. from cmk.gui.plugins.wato.utils.base_modes import mode_url return HTTPRedirect(mode_url(self.back_mode)) return None