def render_snapin(self, snapin: UserSidebarSnapin) -> str: snapin_class = snapin.snapin_type name = snapin_class.type_name() snapin_instance = snapin_class() more_id = "sidebar_snapin_%s" % name show_more = user.get_show_more_setting(more_id) html.open_div(id_="snapin_container_%s" % name, class_=["snapin", ("more" if show_more else "less")]) self._render_snapin_styles(snapin_instance) # When not permitted to open/close snapins, the snapins are always opened if snapin.visible == SnapinVisibility.OPEN or not user.may( "general.configure_sidebar"): style = None else: style = "display:none" toggle_url = "sidebar_openclose.py?name=%s&state=" % name # If the user may modify the sidebar then add code for dragging the snapin head_actions: Dict[str, str] = {} if user.may("general.configure_sidebar"): head_actions = { "onmouseover": "document.body.style.cursor='move';", "onmouseout ": "document.body.style.cursor='';", "onmousedown": "cmk.sidebar.snapin_start_drag(event)", "onmouseup": "cmk.sidebar.snapin_stop_drag(event)", } html.open_div(class_=["head", snapin.visible.value], **head_actions) show_more = snapin_instance.has_show_more_items() may_configure = user.may("general.configure_sidebar") if show_more or may_configure: html.open_div(class_="snapin_buttons") if show_more: html.open_span(class_="moresnapin") html.more_button(more_id, dom_levels_up=4) html.close_span() if may_configure: # Button for closing (removing) a snapin html.open_span(class_="closesnapin") close_url = "sidebar_openclose.py?name=%s&state=off" % name html.icon_button( url=None, title=_("Remove this element"), icon="close", onclick="cmk.sidebar.remove_sidebar_snapin(this, '%s')" % close_url, ) html.close_span() html.close_div() # The heading. A click on the heading mini/maximizes the snapin toggle_actions: Dict[str, str] = {} if user.may("general.configure_sidebar"): toggle_actions = { "onclick": "cmk.sidebar.toggle_sidebar_snapin(this,'%s')" % toggle_url, "onmouseover": "this.style.cursor='pointer'", "onmouseout": "this.style.cursor='auto'", } html.b( textwrap.shorten(snapin_class.title(), width=27, placeholder="..."), class_=["heading"], **toggle_actions, ) if may_configure: # Icon for mini/maximizing html.span( "", class_="minisnapin", title=_("Open/close this element"), onclick="cmk.sidebar.toggle_sidebar_snapin(this, '%s')" % toggle_url, ) # End of header html.close_div() # Now comes the content html.open_div(class_="content", id_="snapin_%s" % name, style=style) refresh_url = "" try: # TODO: Refactor this confusing special case. Add deddicated method or something # to let the snapins make the sidebar know that there is a URL to fetch. url = snapin_instance.show() if url is not None: # Fetch the contents from an external URL. Don't render it on our own. refresh_url = url html.javascript( 'cmk.ajax.get_url("%s", cmk.utils.update_contents, "snapin_%s")' % (refresh_url, name)) except Exception as e: logger.exception("error rendering snapin %s", name) write_snapin_exception(e) html.close_div() html.close_div() return refresh_url
def page(self): watolib.init_wato_datastructures(with_wato_lock=True) if not user.may('wato.diag_host'): raise MKAuthException(_('You are not permitted to perform this action.')) if not transactions.check_transaction(): raise MKAuthException(_("Invalid transaction")) api_request = self.webapi_request() hostname = api_request.get("host") if not hostname: raise MKGeneralException(_('The hostname is missing.')) host = watolib.Host.host(hostname) if not host: raise MKGeneralException(_('The given host does not exist.')) if host.is_cluster(): raise MKGeneralException(_('This view does not support cluster hosts.')) host.need_permission("read") _test = api_request.get('_test') if not _test: raise MKGeneralException(_('The test is missing.')) # Execute a specific test if _test not in dict(ModeDiagHost.diag_host_tests()).keys(): raise MKGeneralException(_('Invalid test.')) # TODO: Use ModeDiagHost._vs_rules() for processing/validation? args: List[str] = [u""] * 13 for idx, what in enumerate([ 'ipaddress', 'snmp_community', 'agent_port', 'snmp_timeout', 'snmp_retries', 'tcp_connect_timeout', ]): args[idx] = api_request.get(what, u"") if api_request.get("snmpv3_use"): snmpv3_use = { u"0": u"noAuthNoPriv", u"1": u"authNoPriv", u"2": u"authPriv", }.get(api_request.get("snmpv3_use", u""), u"") args[7] = snmpv3_use if snmpv3_use != u"noAuthNoPriv": snmpv3_auth_proto = { str(DropdownChoice.option_id("md5")): u"md5", str(DropdownChoice.option_id("sha")): u"sha" }.get(api_request.get("snmpv3_auth_proto", u""), u"") args[8] = snmpv3_auth_proto args[9] = api_request.get("snmpv3_security_name", u"") args[10] = api_request.get("snmpv3_security_password", u"") if snmpv3_use == "authPriv": snmpv3_privacy_proto = { str(DropdownChoice.option_id("DES")): u"DES", str(DropdownChoice.option_id("AES")): u"AES" }.get(api_request.get("snmpv3_privacy_proto", u""), u"") args[11] = snmpv3_privacy_proto args[12] = api_request.get("snmpv3_privacy_password", u"") else: args[9] = api_request.get("snmpv3_security_name", u"") result = watolib.check_mk_automation(host.site_id(), "diag-host", [hostname, _test] + args) return { "next_transid": transactions.fresh_transid(), "status_code": result[0], "output": ensure_str(result[1], errors="replace"), }
def _vs_individual_elements(self) -> List[DictionaryEntry]: if user.may("wato.edit_all_passwords"): admin_element: List[ValueSpec] = [ FixedValue( value=None, title=_("Administrators"), totext=_("Administrators (having the permission " '"Write access to all passwords")'), ) ] else: admin_element = [] elements: List[DictionaryEntry] = [ ( "password", PasswordValuespec( title=_("Password"), allow_empty=False, ), ), ( "owned_by", Alternative( title=_("Editable by"), help=_( "Each password is owned by a group of users which are able to edit, " "delete and use existing passwords."), elements=admin_element + [ DropdownChoice( title=_("Members of the contact group:"), choices=lambda: sorted_contact_group_choices( only_own=True), invalid_choice="complain", empty_text=_( "You need to be member of at least one contact group to be able to " "create a password."), invalid_choice_title=_( "Group not existant or not member"), invalid_choice_error=_( "The choosen group is either not existant " "anymore or you are not a member of this " "group. Please choose another one."), ), ], ), ), ( "shared_with", DualListChoice( title=_("Share with"), help= _("By default only the members of the owner contact group are permitted " "to use a a configured password. It is possible to share a password with " "other groups of users to make them able to use a password in checks." ), choices=sorted_contact_group_choices, autoheight=False, ), ), ] return elements
def may_see(cls) -> bool: return user.may(cls.permission_name())
def __init__(self): super().__init__() if not user.may("wato.rename_hosts"): raise MKGeneralException(_("You don't have the right to rename hosts"))
def render(self, rows, view, group_cells, cells, num_columns, show_checkboxes): repeat_heading_every = 20 # in case column_headers is "repeat" html.open_table(class_='data table') last_group = None odd = "odd" column = 1 group_open = False num_cells = len(cells) if show_checkboxes: num_cells += 1 if not group_cells and view.get("column_headers") != "off": self._show_header_line(cells, num_columns, show_checkboxes) rows_with_ids = [(row_id(view, row), row) for row in rows] groups, rows_with_ids = calculate_view_grouping_of_services( rows_with_ids, row_group_cells=group_cells) visible_row_number = 0 group_hidden, num_grouped_rows = None, 0 for index, row in rows_with_ids: # Show group header, if a new group begins. But only if grouping # is activated if group_cells: this_group = group_value(row, group_cells) if this_group != last_group: if column != 1: # not a the beginning of a new line for _i in range(column - 1, num_columns): html.td('', class_="gap") html.td('', class_="fillup", colspan=num_cells) html.close_tr() column = 1 group_open = True visible_row_number = 0 # paint group header, but only if it is non-empty header_is_empty = True for cell in group_cells: _tdclass, content = cell.render(row) if content: header_is_empty = False break if not header_is_empty: html.open_tr(class_="groupheader") html.open_td(class_="groupheader", colspan=(num_cells * (num_columns + 2) + (num_columns - 1))) html.open_table(class_="groupheader", cellspacing="0", cellpadding="0", border="0") html.open_tr() painted = False for cell in group_cells: if painted: html.td(', ') painted = cell.paint(row) html.close_tr() html.close_table() html.close_td() html.close_tr() odd = "odd" # Table headers if view.get("column_headers") != "off": self._show_header_line(cells, num_columns, show_checkboxes) last_group = this_group # Should we wrap over to a new line? if column >= num_columns + 1: html.close_tr() column = 1 # At the beginning of the line? Beginn new line if column == 1: if view.get("column_headers") == "repeat": if visible_row_number > 0 and visible_row_number % repeat_heading_every == 0: self._show_header_line(cells, num_columns, show_checkboxes) visible_row_number += 1 # In one-column layout we use the state of the service # or host - if available - to color the complete line if num_columns == 1: # render state, if available through whole tr if not row.get('service_description'): state = row.get("host_state", 0) if state > 0: state += 1 # 1 is critical for hosts else: state = row.get("service_state", 0) else: state = 0 if index in groups: group_spec, num_grouped_rows = groups[index] group_hidden = grouped_row_title(index, group_spec, num_grouped_rows, odd, num_cells) odd = "even" if odd == "odd" else "odd" css_classes = [] hide = "" if num_grouped_rows > 0: num_grouped_rows -= 1 if group_hidden: hide = "display:none" if group_hidden is not None and num_grouped_rows == 0: # last row in group css_classes.append("group_end") group_hidden = None odd = "even" if odd == "odd" else "odd" if num_columns > 1: css_classes.append("multicolumn") css_classes += ["%s%d" % (odd, state)] html.open_tr(class_=["data"] + css_classes, style=hide) # Not first columns: Create one empty column as separator else: html.open_td(class_="gap") html.close_td() if show_checkboxes: render_checkbox_td(view, row, num_cells) for cell in cells: cell.paint(row) column += 1 if group_open: for _i in range(column - 1, num_columns): html.td('', class_="gap") html.td('', class_="fillup", colspan=num_cells) html.close_tr() html.close_table() if not user.may("general.act"): return init_rowselect(_get_view_name(view))
def _show_rows(self): rows = self._get_rows() if bool([r for r in rows if r.stats is None]): html.center(_("No data from any site")) return html.open_table(class_=["tacticaloverview"], cellspacing="2", cellpadding="0", border="0") show_stales = self.parameters()["show_stale"] and user.may( "general.see_stales_in_tactical_overview" ) has_stale_objects = bool([r for r in rows if r.what != "events" and r.stats[-1]]) for row in rows: if row.what == "events": amount, problems, unhandled_problems = row.stats stales = 0 # no events open and disabled in local site: don't show events if amount == 0 and not config.mkeventd_enabled: continue else: amount, problems, unhandled_problems, stales = row.stats context_vars = get_context_url_variables(row.context) html.open_tr() html.th(row.title) html.th(_("Problems"), class_="show_more_mode") html.th( html.render_span(_("Unhandled"), class_="more") + html.render_span(_("Unhandled p."), class_="less") ) if show_stales and has_stale_objects: html.th(_("Stale")) html.close_tr() td_class = "col4" if has_stale_objects else "col3" html.open_tr() url = makeuri_contextless(request, row.views.total + context_vars, filename="view.py") html.open_td(class_=["total", td_class]) html.a("%s" % amount, href=url, target="main") html.close_td() for value, ty in [(problems, "handled"), (unhandled_problems, "unhandled")]: url = makeuri_contextless( request, getattr(row.views, ty) + context_vars, filename="view.py", ) html.open_td( class_=[ td_class, "states prob" if value != 0 else None, "show_more_mode" if ty == "handled" else "basic", ] ) link(str(value), url) html.close_td() if show_stales and has_stale_objects: if row.views.stale: url = makeuri_contextless( request, row.views.stale + context_vars, filename="view.py", ) html.open_td(class_=[td_class, "states prob" if stales != 0 else None]) link(str(stales), url) html.close_td() else: html.td(html.render_span("0")) html.close_tr() html.close_table()
def render( self, rows: Rows, show_checkboxes: bool, num_columns: int, show_filters: List[Filter], unfiltered_amount_of_rows: int, ) -> None: view_spec = self.view.spec home = ("mobile.py", "Home", "home") page = request.var("page") if not page: if view_spec.get("mustsearch"): page = "filter" else: page = "data" title = views.view_title(self.view.spec, self.view.context) navbar = [ ("data", _("Results"), "grid", "results_button"), ("filter", _("Filter"), "search", ""), ] if user.may("general.act"): navbar.append(("commands", _("Commands"), "gear", "")) # Should we show a page with context links? context_links = list( views.collect_context_links(self.view, rows, mobile=True, visual_types=["views"])) if context_links: navbar.append(("context", _("Context"), "arrow-r", "")) page_id = "view_" + view_spec["name"] if page == "filter": jqm_page_header(_("Filter / Search"), left_button=home, id_="filter") _show_filter_form(show_filters) jqm_page_navfooter(navbar, "filter", page_id) elif page == "commands": # Page: Commands if user.may("general.act"): jqm_page_header(_("Commands"), left_button=home, id_="commands") show_commands = True if request.has_var("_do_actions"): try: show_commands = do_commands( self.view.datasource.infos[0], rows) except MKUserError as e: html.user_error(e) show_commands = True if show_commands: _show_command_form(self.view.datasource, rows) jqm_page_navfooter(navbar, "commands", page_id) elif page == "data": # Page: data rows of view jqm_page_header( title, left_button=home, right_button=("javascript:document.location.reload();", _("Reload"), "refresh"), id_="data", ) html.open_div(id_="view_results") if len(rows) == 0: html.write_text(_("No hosts/services found.")) else: try: if cmk.gui.view_utils.row_limit_exceeded( unfiltered_amount_of_rows, self.view.row_limit): cmk.gui.view_utils.query_limit_exceeded_warn( self.view.row_limit, user) del rows[self.view.row_limit:] self.view.layout.render( rows, view_spec, self.view.group_cells, self.view.row_cells, num_columns, show_checkboxes and not html.do_actions(), ) except Exception as e: logger.exception("error rendering mobile view") html.write_text(_("Error showing view: %s") % e) html.close_div() jqm_page_navfooter(navbar, "data", page_id) # Page: Context buttons elif page == "context": jqm_page_header(_("Context"), left_button=home, id_="context") _show_context_links(context_links) jqm_page_navfooter(navbar, "context", page_id)
def may_override(): return user.id in config.wato_read_only["rw_users"] or ( request.var("mode") == "read_only" and user.may("wato.set_read_only"))
def _user_menu_topics() -> List[TopicMenuTopic]: quick_items = [ TopicMenuItem( name="ui_theme", title=_("Interface theme"), url='javascript:cmk.sidebar.toggle_user_attribute("ajax_ui_theme.py")', target="", sort_index=10, icon="color_mode", button_title=_get_current_theme_titel(), ), TopicMenuItem( name="sidebar_position", title=_("Sidebar position"), url='javascript:cmk.sidebar.toggle_user_attribute("ajax_sidebar_position.py")', target="", sort_index=20, icon="sidebar_position", button_title=_sidebar_position_title(_get_sidebar_position()), ), ] items = [ TopicMenuItem( name="change_password", title=_("Change password"), url="user_change_pw.py", sort_index=10, icon="topic_change_password", ), TopicMenuItem( name="user_profile", title=_("Edit profile"), url="user_profile.py", sort_index=20, icon="topic_profile", ), TopicMenuItem( name="logout", title=_("Logout"), url="logout.py", sort_index=30, icon="sidebar_logout", ), ] if rulebased_notifications_enabled() and user.may("general.edit_notifications"): items.insert( 1, TopicMenuItem( name="notification_rules", title=_("Notification rules"), url="wato.py?mode=user_notifications_p", sort_index=30, icon="topic_events", ), ) return [ TopicMenuTopic( name="user", title=_("Quick toggle"), # TODO(rb): set correct icon icon="topic_profile", items=quick_items, ), TopicMenuTopic( name="user", title=_("Profile"), icon="topic_profile", items=items, ), ]
def is_visible(self): if user.may("background_jobs.see_foreign_jobs"): return True return user.id == self.get_status().get("user")
def page(self): if not user.may("wato.diag_host"): raise MKAuthException( _("You are not permitted to perform this action.")) if not transactions.check_transaction(): raise MKAuthException(_("Invalid transaction")) api_request = self.webapi_request() hostname = api_request.get("host") if not hostname: raise MKGeneralException(_("The hostname is missing.")) host = watolib.Host.host(hostname) if not host: raise MKGeneralException(_("The given host does not exist.")) if host.is_cluster(): raise MKGeneralException( _("This view does not support cluster hosts.")) host.need_permission("read") _test = api_request.get("_test") if not _test: raise MKGeneralException(_("The test is missing.")) # Execute a specific test if _test not in dict(ModeDiagHost.diag_host_tests()).keys(): raise MKGeneralException(_("Invalid test.")) # TODO: Use ModeDiagHost._vs_rules() for processing/validation? args: List[str] = [""] * 13 for idx, what in enumerate([ "ipaddress", "snmp_community", "agent_port", "snmp_timeout", "snmp_retries", "tcp_connect_timeout", ]): args[idx] = api_request.get(what, "") if api_request.get("snmpv3_use"): snmpv3_use = { "0": "noAuthNoPriv", "1": "authNoPriv", "2": "authPriv", }.get(api_request.get("snmpv3_use", ""), "") args[7] = snmpv3_use if snmpv3_use != "noAuthNoPriv": snmpv3_auth_proto = { str(DropdownChoice.option_id("md5")): "md5", str(DropdownChoice.option_id("sha")): "sha", }.get(api_request.get("snmpv3_auth_proto", ""), "") args[8] = snmpv3_auth_proto args[9] = api_request.get("snmpv3_security_name", "") args[10] = api_request.get("snmpv3_security_password", "") if snmpv3_use == "authPriv": snmpv3_privacy_proto = { str(DropdownChoice.option_id("DES")): "DES", str(DropdownChoice.option_id("AES")): "AES", }.get(api_request.get("snmpv3_privacy_proto", ""), "") args[11] = snmpv3_privacy_proto args[12] = api_request.get("snmpv3_privacy_password", "") else: args[9] = api_request.get("snmpv3_security_name", "") result = diag_host( host.site_id(), hostname, _test, *args, ) return { "next_transid": transactions.fresh_transid(), "status_code": result.return_code, "output": ensure_str(result.response, errors="replace"), }
def _user_is_authorized() -> bool: return user.may("general.agent_pairing")
def may_see_hosts(): return user.may("wato.use") and (user.may("wato.seeall") or user.may("wato.hosts"))
def _render_group(self, rows_with_ids, header, view, group_cells, cells, num_columns, show_checkboxes): repeat_heading_every = 20 # in case column_headers is "repeat" if group_cells: self._show_group_header_table(group_cells, rows_with_ids[0][1]) html.open_table(class_="data") odd = "odd" column_headers = view.get("column_headers") if column_headers != "off": self._show_header_line(cells, show_checkboxes) groups, rows_with_ids = calculate_view_grouping_of_services( rows_with_ids, row_group_cells=None) visible_row_number = 0 group_hidden, num_grouped_rows = None, 0 for index, row in rows_with_ids: if view.get("column_headers") == "repeat": if visible_row_number > 0 and visible_row_number % repeat_heading_every == 0: self._show_header_line(cells, show_checkboxes) visible_row_number += 1 odd = "even" if odd == "odd" else "odd" # state = row.get("service_state", row.get("aggr_state")) state = utils.saveint(row.get("service_state")) if state is None: state = utils.saveint(row.get("host_state", 0)) if state > 0: state += 1 # 1 is critical for hosts num_cells = len(cells) if index in groups: group_spec, num_grouped_rows = groups[index] group_hidden = grouped_row_title(index, group_spec, num_grouped_rows, odd, num_cells) odd = "even" if odd == "odd" else "odd" css_classes = [] if is_stale(row): css_classes.append("stale") hide = "" if num_grouped_rows > 0: num_grouped_rows -= 1 if group_hidden: hide = "display:none" if group_hidden is not None and num_grouped_rows == 0: # last row in group css_classes.append("group_end") group_hidden = None css_classes.append("%s%d" % (odd, state)) html.open_tr(class_=["data"] + css_classes, style=hide) if show_checkboxes: render_checkbox_td(view, row, num_cells) for cell in cells: cell.paint(row) html.close_tr() html.close_table() # Don't make rows selectable when no commands can be fired # Ignore "C" display option here. Otherwise the rows will not be selectable # after view reload. if not user.may("general.act"): return init_rowselect(_get_view_name(view))
def _may_edit_configvar(self, varname): if varname in ["actions"]: return user.may("wato.add_or_modify_executables") return True
def render(self, rows, view, group_cells, cells, num_columns, show_checkboxes): html.open_table(class_="data tiled") last_group = None group_open = False for row in rows: # Show group header if group_cells: this_group = group_value(row, group_cells) if this_group != last_group: # paint group header if group_open: html.close_td() html.close_tr() html.open_tr() html.open_td() html.open_table(class_="groupheader") html.open_tr(class_="groupheader") painted = False for cell in group_cells: if painted: html.td(', ') painted = cell.paint(row) html.close_tr() html.close_table() html.close_td() html.close_tr() html.open_tr() html.open_td(class_="tiles") group_open = True last_group = this_group # background color of tile according to item state state = row.get("service_state", -1) if state == -1: hbc = row.get("host_has_been_checked", 1) if hbc: state = row.get("host_state", 0) sclass = "hhstate%d" % state else: sclass = "hhstatep" else: hbc = row.get("service_has_been_checked", 1) if hbc: sclass = "sstate%d" % state else: sclass = "sstatep" if not group_open: html.open_tr() html.open_td(class_="tiles") group_open = True html.open_div(class_=["tile", sclass]) html.open_table() # We need at least five cells if len(cells) < 5: cells = cells + ([EmptyCell(view)] * (5 - len(cells))) rendered = [cell.render(row) for cell in cells] html.open_tr() html.open_td(class_=["tl", rendered[1][0]]) if show_checkboxes: render_checkbox(view, row, len(cells) - 1) html.write_text(rendered[1][1]) html.close_td() html.open_td(class_=["tr", rendered[2][0]]) html.write_text(rendered[2][1]) html.close_td() html.close_tr() html.open_tr() html.open_td(colspan=2, class_=["center", rendered[0][0]]) html.write_text(rendered[0][1]) html.close_td() html.close_tr() for css, cont in rendered[5:]: html.open_tr() html.open_td(colspan=2, class_=["cont", css]) html.write_text(cont) html.close_td() html.close_tr() html.open_tr() html.open_td(class_=["bl", rendered[3][0]]) html.write_text(rendered[3][1]) html.close_td() html.open_td(class_=["br", rendered[4][0]]) html.write_text(rendered[4][1]) html.close_td() html.close_tr() html.close_table() html.close_div() if group_open: html.close_td() html.close_tr() html.close_table() if not user.may("general.act"): return init_rowselect(_get_view_name(view))
def page_menu_host_entries(mode_name: str, host: CREHost) -> Iterator[PageMenuEntry]: if mode_name != "edit_host": yield PageMenuEntry( title=_("Properties"), icon_name="edit", item=make_simple_link( watolib.folder_preserving_link([("mode", "edit_host"), ("host", host.name())])), ) if mode_name != "inventory": yield PageMenuEntry( title=_("Service configuration"), icon_name="services", item=make_simple_link( watolib.folder_preserving_link([("mode", "inventory"), ("host", host.name())])), ) if mode_name != "diag_host" and not host.is_cluster(): yield PageMenuEntry( title=_("Connection tests"), icon_name="diagnose", item=make_simple_link( watolib.folder_preserving_link([("mode", "diag_host"), ("host", host.name())])), ) if mode_name != "object_parameters" and user.may("wato.rulesets"): yield PageMenuEntry( title=_("Effective parameters"), icon_name="rulesets", item=make_simple_link( watolib.folder_preserving_link([("mode", "object_parameters"), ("host", host.name())])), ) if mode_name == "object_parameters" or mode_name == "edit_host" and user.may( "wato.rulesets"): yield PageMenuEntry( title=_("Rules"), icon_name="rulesets", item=make_simple_link( makeuri_contextless( request, [ ("mode", "rule_search"), ("filled_in", "search"), ("search_p_ruleset_deprecated", "OFF"), ("search_p_rule_host_list_USE", "ON"), ("search_p_rule_host_list", host.name()), ], filename="wato.py", )), ) yield make_host_status_link(host_name=host.name(), view_name="hoststatus") if user.may("wato.rulesets") and host.is_cluster(): yield PageMenuEntry( title=_("Clustered services"), icon_name="rulesets", item=make_simple_link( watolib.folder_preserving_link([("mode", "edit_ruleset"), ("varname", "clustered_services")])), ) if watolib.has_agent_bakery() and user.may("wato.download_agents"): yield PageMenuEntry( title=_("Monitoring agent"), icon_name="agents", item=make_simple_link( watolib.folder_preserving_link([("mode", "agent_of_host"), ("host", host.name())])), ) if mode_name == "edit_host" and not host.locked(): if user.may("wato.rename_hosts"): yield PageMenuEntry( title=_("Rename"), icon_name="rename_host", item=make_simple_link( watolib.folder_preserving_link([("mode", "rename_host"), ("host", host.name())])), ) if user.may("wato.manage_hosts") and user.may("wato.clone_hosts"): yield PageMenuEntry( title=_("Clone"), icon_name="insert", item=make_simple_link(host.clone_url()), ) yield PageMenuEntry( title=_("Delete"), icon_name="delete", item=make_simple_link( make_confirm_link( url=makeactionuri(request, transactions, [("delete", "1")]), message=_( "Do you really want to delete the host <tt>%s</tt>?") % host.name(), )), ) if user.may("wato.auditlog"): yield PageMenuEntry( title=_("Audit log"), icon_name="auditlog", item=make_simple_link( make_object_audit_log_url(host.object_ref())), )
def _activation_status(self): with table_element("site-status", searchable=False, sortable=False, css="activation") as table: for site_id, site in sort_sites(activation_sites()): table.row() site_status, status = self._get_site_status(site_id, site) is_online = self._site_is_online(status) is_logged_in = self._site_is_logged_in(site_id, site) has_foreign = self._site_has_foreign_changes(site_id) can_activate_all = not has_foreign or user.may( "wato.activateforeign") # Disable actions for offline sites and not logged in sites if not is_online or not is_logged_in: can_activate_all = False need_restart = self._is_activate_needed(site_id) need_sync = self.is_sync_needed(site_id) need_action = need_restart or need_sync nr_changes = len(self._changes_of_site(site_id)) # Activation checkbox table.cell("", css="buttons") if can_activate_all and nr_changes: html.checkbox("site_%s" % site_id, need_action, cssclass="site_checkbox") # Iconbuttons table.cell(_("Actions"), css="buttons") if user.may("wato.sites"): edit_url = watolib.folder_preserving_link([ ("mode", "edit_site"), ("site", site_id) ]) html.icon_button(edit_url, _("Edit the properties of this site"), "edit") # State if can_activate_all and need_sync: html.icon_button( url="javascript:void(0)", id_="activate_%s" % site_id, cssclass="activate_site", title= _("This site is not update and needs a replication. Start it now." ), icon="need_replicate", onclick='cmk.activation.activate_changes("site", "%s")' % site_id, ) if can_activate_all and need_restart: html.icon_button( url="javascript:void(0)", id_="activate_%s" % site_id, cssclass="activate_site", title= _("This site needs a restart for activating the changes. Start it now." ), icon="need_restart", onclick='cmk.activation.activate_changes("site", "%s")' % site_id, ) if can_activate_all and not need_action: html.icon("siteuptodate", _("This site is up-to-date.")) site_url = site.get("multisiteurl") if site_url: html.icon_button( site_url, _("Open this site's local web user interface"), "url", target="_blank", ) table.cell(_("Site"), site.get("alias", site_id), css="narrow nobr") # Livestatus table.cell(_("Status"), css="narrow nobr") html.status_label(content=status, status=status, title=_("This site is %s") % status) # Livestatus-/Checkmk-Version table.cell(_("Version"), site_status.get("livestatus_version", ""), css="narrow nobr") table.cell(_("Changes"), "%d" % nr_changes, css="number narrow nobr") table.cell(_("Progress"), css="repprogress") html.open_div(id_="site_%s_status" % site_id, class_=["msg"]) html.close_div() html.open_div(id_="site_%s_progress" % site_id, class_=["progress"]) html.close_div() table.cell(_("Details"), css="details") html.open_div(id_="site_%s_details" % site_id) last_state = self._last_activation_state(site_id) if not is_logged_in: html.write_text(_("Is not logged in.") + " ") if not last_state: html.write_text(_("Has never been activated")) elif (need_action and last_state["_state"] == cmk.gui.watolib.activate_changes.STATE_SUCCESS): html.write_text(_("Activation needed")) else: html.javascript( "cmk.activation.update_site_activation_state(%s);" % json.dumps(last_state)) html.close_div()
def _wato_page_handler(current_mode: str, mode_permissions: Optional[List[PermissionName]], mode_class: Type[WatoMode]) -> None: # Check general permission for this mode if mode_permissions is not None and not user.may("wato.seeall"): _ensure_mode_permissions(mode_permissions) mode = mode_class() # Do actions (might switch mode) if transactions.is_transaction(): try: user.need_permission("wato.edit") # Even if the user has seen this mode because auf "seeall", # he needs an explicit access permission for doing changes: if user.may("wato.seeall"): if mode_permissions: _ensure_mode_permissions(mode_permissions) if (cmk.gui.watolib.read_only.is_enabled() and not cmk.gui.watolib.read_only.may_override()): raise MKUserError(None, cmk.gui.watolib.read_only.message()) result = mode.action() if isinstance(result, (tuple, str, bool)): raise MKGeneralException( f'WatoMode "{current_mode}" returns unsupported return value: {result!r}' ) # We assume something has been modified and increase the config generation ID by one. update_config_generation() if config.wato_use_git: do_git_commit() # Handle two cases: # a) Don't render the page content after action # (a confirm dialog is displayed by the action, or a non-HTML content was sent) # b) Redirect to another page if isinstance(result, FinalizeRequest): raise result except MKUserError as e: user_errors.add(e) except MKAuthException as e: user_errors.add(MKUserError(None, e.args[0])) breadcrumb = make_main_menu_breadcrumb( mode.main_menu()) + mode.breadcrumb() page_menu = mode.page_menu(breadcrumb) wato_html_head( title=mode.title(), breadcrumb=breadcrumb, page_menu=page_menu, show_body_start=display_options.enabled(display_options.H), show_top_heading=display_options.enabled(display_options.T), ) if not transactions.is_transaction() or ( cmk.gui.watolib.read_only.is_enabled() and cmk.gui.watolib.read_only.may_override()): _show_read_only_warning() # Show outcome of failed action on this page html.show_user_errors() # Show outcome of previous page (that redirected to this one) for message in get_flashed_messages(): html.show_message(message) # Show content mode.handle_page() if is_sidebar_reload_needed(): html.reload_whole_page() wato_html_footer(show_body_end=display_options.enabled(display_options.H))
def may_acknowledge(): return user.may("general.acknowledge_werks")
def _wsgi_app(self, environ: WSGIEnvironment, start_response: StartResponse) -> WSGIResponse: urls = self.url_map.bind_to_environ(environ) endpoint: Optional[Endpoint] = None try: result: Tuple[str, Mapping[str, Any]] = urls.match(return_rule=False) endpoint_ident, matched_path_args = result # pylint: disable=unpacking-non-sequence wsgi_app = self.endpoints[endpoint_ident] if isinstance(wsgi_app, Authenticate): endpoint = wsgi_app.endpoint # Remove _path again (see Submount above), so the validators don't go crazy. path_args = {key: value for key, value in matched_path_args.items() if key != "_path"} # This is an implicit dependency, as we only know the args at runtime, but the # function at setup-time. environ[ARGS_KEY] = path_args req = Request(environ) resp = Response() with AppContext(self), RequestContext( req=req, resp=resp, funnel=OutputFunnel(resp), config_obj=config.make_config_object(config.get_default_config()), endpoint=endpoint, user=LoggedInNobody(), display_options=DisplayOptions(), ), cmk.utils.store.cleanup_locks(), sites.cleanup_connections(): config.initialize() load_dynamic_permissions() return wsgi_app(environ, start_response) except ProblemException as exc: return exc(environ, start_response) except HTTPException as exc: # We don't want to log explicit HTTPExceptions as these are intentional. assert isinstance(exc.code, int) return problem( status=exc.code, title=http.client.responses[exc.code], detail=str(exc), )(environ, start_response) except MKException as exc: if self.debug: raise return problem( status=EXCEPTION_STATUS.get(type(exc), 500), title="An exception occurred.", detail=str(exc), )(environ, start_response) except Exception as exc: crash = APICrashReport.from_exception() crash_reporting.CrashReportStore().save(crash) logger.exception("Unhandled exception (Crash-ID: %s)", crash.ident_to_text()) if self.debug: raise request = Request(environ) site = config.omd_site() query_string = urllib.parse.urlencode( [ ("crash_id", (crash.ident_to_text())), ("site", site), ] ) crash_url = f"{request.host_url}{site}/check_mk/crash.py?{query_string}" crash_details = { "crash_id": (crash.ident_to_text()), "crash_report": { "href": crash_url, "method": "get", "rel": "cmk/crash-report", "type": "text/html", }, } if user.may("general.see_crash_reports"): crash_details["stack_trace"] = traceback.format_exc().split("\n") return problem( status=500, title=http.client.responses[500], detail=str(exc), ext=crash_details, )(environ, start_response)
def _may_see_failed_notifications() -> bool: return user.may("general.see_failed_notifications") or user.may( "general.see_failed_notifications_24h")
def _wsgi_app(self, environ: WSGIEnvironment, start_response): urls = self.url_map.bind_to_environ(environ) try: wsgi_app, path_args = urls.match() # Remove this again (see Submount above), so the validators don't go crazy. del path_args['_path'] # This is an implicit dependency, as we only know the args at runtime, but the # function at setup-time. environ[ARGS_KEY] = path_args return wsgi_app(environ, start_response) except HTTPException as exc: # We don't want to log explicit HTTPExceptions as these are intentional. assert isinstance(exc.code, int) return problem( status=exc.code, title=http.client.responses[exc.code], detail=str(exc), )(environ, start_response) except MKException as exc: if self.debug: raise return problem( status=EXCEPTION_STATUS.get(type(exc), 500), title="An exception occurred.", detail=str(exc), )(environ, start_response) except Exception as exc: crash = APICrashReport.from_exception() crash_reporting.CrashReportStore().save(crash) logger.exception("Unhandled exception (Crash-ID: %s)", crash.ident_to_text()) if self.debug: raise request = Request(environ) site = config.omd_site() query_string = urllib.parse.urlencode([ ("crash_id", (crash.ident_to_text())), ("site", site), ]) crash_url = f"{request.host_url}{site}/check_mk/crash.py?{query_string}" crash_details = { 'crash_id': (crash.ident_to_text()), 'crash_report': { 'href': crash_url, 'method': 'get', 'rel': 'cmk/crash-report', 'type': 'text/html', }, } if user.may("general.see_crash_reports"): crash_details['stack_trace'] = traceback.format_exc().split( "\n") return problem( status=500, title=http.client.responses[500], detail=str(exc), ext=crash_details, )(environ, start_response)
def may_edit(self): return user.may("wato.manage_hosts")
def may_see_category(self, category: str) -> bool: return user.may("wato.use") and self._category_permissions.get( category, True)