def page(self): if not self._job_snapshot.exists(): # Skip if snapshot doesnt exists pass elif self._job_snapshot.is_active(): # Still running html.message( HTML(_("User synchronization currently running: ")) + self._job_details_link()) url = html.makeuri([]) html.immediate_browser_redirect(2, url) elif self._job_snapshot.state() == gui_background_job.background_job.JobStatusStates.FINISHED \ and not self._job_snapshot.acknowledged_by(): # Just finished, auto-acknowledge userdb.UserSyncBackgroundJob().acknowledge(config.user.id) #html.message(_("User synchronization successful")) elif not self._job_snapshot.acknowledged_by() and self._job_snapshot.has_exception(): # Finished, but not OK - show info message with links to details html.show_warning( HTML(_("Last user synchronization ran into an exception: ")) + self._job_details_link()) self._show_user_list()
def query_limit_exceeded_warn(limit: Optional[int], user_config: LoggedInUser) -> None: """Compare query reply against limits, warn in the GUI about incompleteness""" text = HTML(_("Your query produced more than %d results. ") % limit) if request.get_ascii_input( "limit", "soft") == "soft" and user_config.may("general.ignore_soft_limit"): text += html.render_a( _("Repeat query and allow more results."), target="_self", href=makeuri(request, [("limit", "hard")]), ) elif request.get_ascii_input("limit") == "hard" and user_config.may( "general.ignore_hard_limit"): text += html.render_a( _("Repeat query without limit."), target="_self", href=makeuri(request, [("limit", "none")]), ) text += escaping.escape_to_html_permissive(" " + _( "<b>Note:</b> the shown results are incomplete and do not reflect the sort order." )) html.show_warning(text)
def _show_form(self, profile_changed: bool) -> None: assert config.user.id is not None users = userdb.load_users() if profile_changed: html.reload_sidebar() html.show_message(_("Successfully updated user profile.")) # Ensure theme changes are applied without additional user interaction html.immediate_browser_redirect(0.5, makeuri(global_request, [])) if html.has_user_errors(): html.show_user_errors() user = users.get(config.user.id) if user is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(self._page_title()) forms.section(_("Name"), simple=True) html.write_text(user.get("alias", config.user.id)) select_language(user) # Let the user configure how he wants to be notified rulebased_notifications = rulebased_notifications_enabled() if (not rulebased_notifications and config.user.may('general.edit_notifications') and user.get("notifications_enabled")): forms.section(_("Notifications")) html.help( _("Here you can configure how you want to be notified about host and service problems and " "other monitoring events.")) watolib.get_vs_flexible_notifications().render_input( "notification_method", user.get("notification_method")) if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): vs = attr.valuespec() forms.section(_u(vs.title())) value = user.get(name, vs.default_value()) if not attr.permission() or config.user.may( attr.permission()): vs.render_input("ua_" + name, value) html.help(_u(vs.help())) else: html.write(vs.value_to_text(value)) forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def _load_structured_data_tree( tree_type: Literal["inventory", "status_data"], hostname: Optional[HostName]) -> Optional[StructuredDataNode]: """Load data of a host, cache it in the current HTTP request""" if not hostname: return None inventory_tree_cache = g.setdefault(tree_type, {}) if hostname in inventory_tree_cache: inventory_tree = inventory_tree_cache[hostname] else: if '/' in hostname: # just for security reasons return None tree_store = StructuredDataStore( Path(cmk.utils.paths.inventory_output_dir) if tree_type == "inventory" else Path(cmk.utils.paths.status_data_dir)) try: inventory_tree = tree_store.load(host_name=hostname) except Exception as e: if config.debug: html.show_warning("%s" % e) raise LoadStructuredDataError() inventory_tree_cache[hostname] = inventory_tree return inventory_tree
def generate_dropdown_results(self): try: self._query_data() except TooManyRowsError as e: html.show_warning(e) self._evaluate_results() self._render_dropdown_elements()
def _show_form(self, profile_changed: bool) -> None: assert config.user.id is not None users = userdb.load_users() change_reason = html.request.get_ascii_input('reason') if change_reason == 'expired': html.p( _('Your password is too old, you need to choose a new password.' )) elif change_reason == 'enforced': html.p( _('You are required to change your password before proceeding.' )) if profile_changed: html.show_message(_("Your password has been changed.")) if change_reason: raise HTTPRedirect( html.request.get_str_input_mandatory( '_origtarget', 'index.py')) if html.has_user_errors(): html.show_user_errors() user = users.get(config.user.id) if user is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return locked_attributes = userdb.locked_attributes(user.get('connector')) if "password" in locked_attributes: raise MKUserError( "cur_password", _("You can not change your password, because it is " "managed by another system.")) html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(self._page_title()) forms.section(_("Current Password")) html.password_input('cur_password', autocomplete="new-password") forms.section(_("New Password")) html.password_input('password', autocomplete="new-password") forms.section(_("New Password Confirmation")) html.password_input('password2', autocomplete="new-password") forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def page(self): is_configured = self._is_configured() is_configured_globally = self._varname in self._global_settings default_values = watolib.ABCConfigDomain.get_all_default_globals() defvalue = default_values[self._varname] value = self._current_settings.get( self._varname, self._global_settings.get(self._varname, defvalue)) hint = self._config_variable.hint() if hint: html.show_warning(hint) html.begin_form("value_editor", method="POST") title = self._valuespec.title() assert isinstance(title, str) forms.header(title) if not config.wato_hide_varnames: forms.section(_("Configuration variable:")) html.tt(self._varname) forms.section(_("Current setting")) self._valuespec.render_input("ve", value) self._valuespec.set_focus("ve") html.help(self._valuespec.help()) if is_configured_globally: self._show_global_setting() forms.section(_("Factory setting")) html.write_html(HTML(self._valuespec.value_to_text(defvalue))) forms.section(_("Current state")) if is_configured_globally: html.write_text( _("This variable is configured in <a href=\"%s\">global settings</a>." ) % ("wato.py?mode=edit_configvar&varname=%s" % self._varname)) elif not is_configured: html.write_text(_("This variable is at factory settings.")) else: curvalue = self._current_settings[self._varname] if is_configured_globally and curvalue == self._global_settings[ self._varname]: html.write_text( _("Site setting and global setting are identical.")) elif curvalue == defvalue: html.write_text( _("Your setting and factory settings are identical.")) else: html.write(self._valuespec.value_to_text(curvalue)) forms.end() html.hidden_fields() html.end_form()
def _show_form(self, profile_changed: bool) -> None: assert config.user.id is not None users = userdb.load_users() if profile_changed: flash(_("Successfully updated user profile.")) # Ensure theme changes are applied without additional user interaction html.reload_whole_page() if html.has_user_errors(): html.show_user_errors() user = users.get(config.user.id) if user is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(_("Personal settings")) forms.section(_("Name"), simple=True) html.write_text(user.get("alias", config.user.id)) select_language(user) # Let the user configure how he wants to be notified rulebased_notifications = rulebased_notifications_enabled() if (not rulebased_notifications and config.user.may('general.edit_notifications') and user.get("notifications_enabled")): forms.section(_("Notifications")) html.help( _("Here you can configure how you want to be notified about host and service problems and " "other monitoring events.")) watolib.get_vs_flexible_notifications().render_input( "notification_method", user.get("notification_method")) if config.user.may('general.edit_user_attributes'): custom_user_attr_topics = get_user_attributes_by_topic() _show_custom_user_attr(user, custom_user_attr_topics.get("personal", [])) forms.header(_("User interface settings")) _show_custom_user_attr( user, custom_user_attr_topics.get("interface", [])) forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def _show_form(self) -> None: assert user.id is not None users = userdb.load_users() user_spec: Optional[UserSpec] = users.get(user.id) if user_spec is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(_("Personal settings")) forms.section(_("Name"), simple=True) html.write_text(user_spec.get("alias", user.id)) select_language(user_spec) # Let the user configure how he wants to be notified rulebased_notifications = rulebased_notifications_enabled() if ( not rulebased_notifications and user.may("general.edit_notifications") and user_spec.get("notifications_enabled") ): forms.section(_("Notifications")) html.help( _( "Here you can configure how you want to be notified about host and service problems and " "other monitoring events." ) ) watolib.get_vs_flexible_notifications().render_input( "notification_method", user_spec.get("notification_method") ) if user.may("general.edit_user_attributes"): custom_user_attr_topics = get_user_attributes_by_topic() _show_custom_user_attr(user_spec, custom_user_attr_topics.get("personal", [])) forms.header(_("User interface settings")) _show_custom_user_attr(user_spec, custom_user_attr_topics.get("interface", [])) forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def _show_form(self) -> None: assert user.id is not None users = userdb.load_users() change_reason = request.get_ascii_input("reason") if change_reason == "expired": html.p( _("Your password is too old, you need to choose a new password." )) elif change_reason == "enforced": html.p( _("You are required to change your password before proceeding." )) user_spec = users.get(user.id) if user_spec is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return locked_attributes = userdb.locked_attributes( user_spec.get("connector")) if "password" in locked_attributes: raise MKUserError( "cur_password", _("You can not change your password, because it is " "managed by another system."), ) html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(self._page_title()) forms.section(_("Current Password")) html.password_input("cur_password", autocomplete="new-password") forms.section(_("New Password")) html.password_input("password", autocomplete="new-password") forms.section(_("New Password Confirmation")) html.password_input("password2", autocomplete="new-password") forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def warn_about_local_files(info): if info["crash_type"] == "check": files = [] for filepath, _lineno, _func, _line in info["exc_traceback"]: if "/local/" in filepath: files.append(filepath) if files: warn_text = _( "The following files located in the local hierarchy of your site are involved in this exception:" ) warn_text += html.render_ul(HTML("\n").join(map(html.render_li, files))) warn_text += _("Maybe these files are not compatible with your current Check_MK " "version. Please verify and only report this crash when you think " "this should be working.") html.show_warning(warn_text)
def _show_customized_builtin_warning(self): customized = [ tg.id for tg in self._effective_config.tag_groups if self._builtin_config.tag_group_exists(tg.id) and self._tag_config.tag_group_exists(tg.id) ] if not customized: return html.show_warning( _("You have customized the tag group(s) <tt>%s</tt> in your tag configuration. " "In current Checkmk versions these are <i>builtin</i> tag groups which " "can not be customized anymore. Your customized tag group will work for " "the moment, but needs to be migrated until 1.7. With 1.7 it won't work " "anymore." % ", ".join(customized)))
def _activation_form(self): if not config.user.may("wato.activate"): html.show_warning( _("You are not permitted to activate configuration changes.")) return if not self._changes: html.show_message(_("Currently there are no changes to activate.")) return if not config.user.may("wato.activateforeign") \ and self._has_foreign_changes_on_any_site(): html.show_warning( _("Sorry, you are not allowed to activate changes of other users." )) return valuespec = self._vs_activation() html.begin_form("activate", method="POST", action="") html.hidden_field("activate_until", self._get_last_change_id(), id_="activate_until") forms.header(valuespec.title()) valuespec.render_input("activate", self._value) valuespec.set_focus("activate") html.help(valuespec.help()) if self.has_foreign_changes(): if config.user.may("wato.activateforeign"): html.show_warning( _("There are some changes made by your colleagues that you will " "activate if you proceed. You need to enable the checkbox above " "to confirm the activation of these changes.")) else: html.show_warning( _("There are some changes made by your colleagues that you can not " "activate because you are not permitted to. You can only activate " "the changes on the sites that are not affected by these changes. " "<br>" "If you need to activate your changes on all sites, please contact " "a permitted user to do it for you.")) forms.end() html.jsbutton("activate_affected", _("Activate affected"), "cmk.activation.activate_changes(\"affected\")", cssclass="hot") html.jsbutton("activate_selected", _("Activate selected"), "cmk.activation.activate_changes(\"selected\")") html.hidden_fields() html.end_form()
def query_limit_exceeded_warn(limit, user_config): """Compare query reply against limits, warn in the GUI about incompleteness""" text = _("Your query produced more than %d results. ") % limit if html.get_ascii_input( "limit", "soft") == "soft" and user_config.may("general.ignore_soft_limit"): text += html.render_a(_('Repeat query and allow more results.'), target="_self", href=html.makeuri([("limit", "hard")])) elif html.get_ascii_input("limit") == "hard" and user_config.may( "general.ignore_hard_limit"): text += html.render_a(_('Repeat query without limit.'), target="_self", href=html.makeuri([("limit", "none")])) text += " " + _( "<b>Note:</b> the shown results are incomplete and do not reflect the sort order." ) html.show_warning(text)
def _activation_form(self): if not config.user.may("wato.activate"): html.show_warning( _("You are not permitted to activate configuration changes.")) return if not self._changes: return if not config.user.may("wato.activateforeign") \ and self._has_foreign_changes_on_any_site(): html.show_warning( _("Sorry, you are not allowed to activate changes of other users." )) return valuespec = _vs_activation(self.title(), self.has_foreign_changes()) html.begin_form("activate", method="POST", action="") html.hidden_field("activate_until", self._get_last_change_id(), id_="activate_until") if valuespec: title = valuespec.title() assert title is not None forms.header(title) valuespec.render_input("activate", self._value) valuespec.set_focus("activate") html.help(valuespec.help()) if self.has_foreign_changes(): if config.user.may("wato.activateforeign"): html.show_warning( _("There are some changes made by your colleagues that you will " "activate if you proceed. You need to enable the checkbox above " "to confirm the activation of these changes.")) else: html.show_warning( _("There are some changes made by your colleagues that you can not " "activate because you are not permitted to. You can only activate " "the changes on the sites that are not affected by these changes. " "<br>" "If you need to activate your changes on all sites, please contact " "a permitted user to do it for you.")) forms.end() html.hidden_field("selection_id", weblib.selection_id()) html.hidden_fields() html.end_form() init_rowselect(self.name())
def _ajax_search(self) -> None: """Generate the search result list""" query = _maybe_strip(html.request.get_unicode_input('q')) if not query: return try: results = self._quicksearch_manager.generate_results(query) QuicksearchResultRenderer().show(results, query) except TooManyRowsError as e: html.show_warning(str(e)) except MKException as e: html.show_error("%s" % e) except Exception: logger.exception("error generating quicksearch results") if config.debug: raise html.show_error(traceback.format_exc())
def _load_inventory_tree(hostname): # Load data of a host, cache it in the current HTTP request if not hostname: return inventory_tree_cache = g.setdefault("inventory", {}) if hostname in inventory_tree_cache: inventory_tree = inventory_tree_cache[hostname] else: if '/' in hostname: # just for security reasons return cache_path = "%s/inventory/%s" % (cmk.utils.paths.var_dir, hostname) try: inventory_tree = StructuredDataTree().load_from(cache_path) except Exception as e: if config.debug: html.show_warning(e) raise LoadStructuredDataError() inventory_tree_cache[hostname] = inventory_tree return inventory_tree
def show(self): host = self._dashlet_spec['context'].get("host", html.request.var("host")) if not host: raise MKUserError('host', _('Missing needed host parameter.')) service = self._dashlet_spec['context'].get("service") if not service: service = "_HOST_" metric = self._dashlet_spec["metric"] if "metric" in self._dashlet_spec else "" site = self._get_site_by_host_name(host) metric_spec = {"site": site, "host": host, "service": service, "metric": metric} svc_url = "view.py?view_name=service&site=%s&host=%s&service=%s" % ( html.urlencode(site), html.urlencode(host), html.urlencode(service)) links = { "site": html.render_a(site, "view.py?view_name=sitehosts&site=%s" % (html.urlencode(site))), "host": html.render_a( host, "view.py?view_name=host&site=%s&host=%s" % (html.urlencode(site), html.urlencode(host))), "service": html.render_a(service, svc_url) } render_options = self._dashlet_spec["metric_render_options"] metrics = self._query_for_metrics_of_host(site, host, service) t_metrics = self._get_translated_metrics_from_perf_data(metrics) chosen_metric_name, metric_choices = self._get_chosen_metric(t_metrics, metric) svc_state = metrics["svc_state"] html.open_div(class_="metric") if metrics: if chosen_metric_name: chosen_metric = t_metrics[chosen_metric_name] titles = self._get_titles(metric_spec, links, render_options) self._render_metric_content(chosen_metric, render_options, titles, svc_state, svc_url) else: html.open_div(class_="no_metric_match") if metric_choices: # TODO: Fix this handling of no available/matching metric # after the implementation of host/site contexts warning_txt = HTML( _("The given metric \"%s\" could not be found.\ For the selected service \"%s\" you can choose from the following metrics:" % (metric, service))) warning_txt += html.render_ul("".join( [str(html.render_li(b)) for _a, b in metric_choices])) html.show_warning(warning_txt) else: html.show_warning(_("No metric could be found.")) html.close_div() else: html.show_warning(_("There are no metrics meeting your context filters.")) html.close_div()
def matches_search(self, search_options): if "rule_folder" in search_options and self.folder.name() not in self._get_search_folders( search_options): return False if "rule_disabled" in search_options and search_options[ "rule_disabled"] != self.is_disabled(): return False if "rule_predefined_condition" in search_options and search_options[ "rule_predefined_condition"] != self.predefined_condition_id(): return False if "rule_ineffective" in search_options and search_options[ "rule_ineffective"] != self.is_ineffective(): return False if not _match_search_expression(search_options, "rule_description", self.description()): return False if not _match_search_expression(search_options, "rule_comment", self.comment()): return False value_text = None try: value_text = "%s" % self.ruleset.valuespec().value_to_text(self.value) except Exception as e: logger.exception("error searching ruleset %s", self.ruleset.title()) html.show_warning( _("Failed to search rule of ruleset '%s' in folder '%s' (%r): %s") % (self.ruleset.title(), self.folder.title(), self.to_config(), e)) if value_text is not None and not _match_search_expression(search_options, "rule_value", value_text): return False if self.conditions.host_list and not _match_one_of_search_expression( search_options, "rule_host_list", self.conditions.host_list[0]): return False if self.conditions.item_list and not _match_one_of_search_expression( search_options, "rule_item_list", self.conditions.item_list[0]): return False to_search = [ self.comment(), self.description(), ] + (self.conditions.host_list[0] if self.conditions.host_list else []) + (self.conditions.item_list[0] if self.conditions.item_list else []) if value_text is not None: to_search.append(value_text) if not _match_one_of_search_expression(search_options, "fulltext", to_search): return False searching_host_tags = search_options.get("rule_hosttags") if searching_host_tags: for host_tag in searching_host_tags: if host_tag not in self.conditions.tag_list: return False return True
def render_bi_availability(title, aggr_rows): # type: (Text, Rows) -> None config.user.need_permission("general.see_availability") av_mode = html.request.get_ascii_input_mandatory("av_mode", "availability") avoptions = get_availability_options_from_url("bi") if av_mode == "timeline": title = _("Timeline of") + " " + title else: title = _("Availability of") + " " + title if html.output_format != "csv_export": html.body_start(title) html.top_heading(title) html.begin_context_buttons() html.toggle_button("avoptions", False, "painteroptions", _("Configure details of the report")) html.context_button(_("Status View"), html.makeuri([("mode", "status")]), "status") if config.reporting_available() and config.user.may( "general.reporting"): html.context_button(_("Export as PDF"), html.makeuri([], filename="report_instant.py"), "report") if config.user.may("general.csv_export"): html.context_button( _("Export as CSV"), html.makeuri([("output_format", "csv_export")]), "download_csv") if av_mode == "timeline": html.context_button(_("Availability"), html.makeuri([("av_mode", "availability")]), "availability") elif len(aggr_rows) == 1: aggr_name = aggr_rows[0]["aggr_name"] aggr_group = aggr_rows[0]["aggr_group"] timeline_url = html.makeuri([("av_mode", "timeline"), ("av_aggr_name", aggr_name), ("av_aggr_group", aggr_group)]) html.context_button(_("Timeline"), timeline_url, "timeline") html.end_context_buttons() avoptions = render_availability_options("bi") if not html.has_user_errors(): logrow_limit = avoptions["logrow_limit"] if logrow_limit == 0: livestatus_limit = None else: livestatus_limit = (len(aggr_rows) * logrow_limit) spans = [] # type: List[AVSpan] # iterate all aggregation rows timewarpcode = HTML() timewarp = html.request.get_integer_input("timewarp") has_reached_logrow_limit = False timeline_containers, fetched_rows = availability.get_timeline_containers( aggr_rows, avoptions, timewarp, livestatus_limit + 1 if livestatus_limit is not None else None) if livestatus_limit and fetched_rows > livestatus_limit: has_reached_logrow_limit = True for timeline_container in timeline_containers: tree = timeline_container.aggr_tree these_spans = timeline_container.timeline timewarp_tree_state = timeline_container.timewarp_state spans += these_spans # render selected time warp for the corresponding aggregation row (should be matched by only one) if timewarp and timewarp_tree_state: state, assumed_state, node, _subtrees = timewarp_tree_state eff_state = state if assumed_state is not None: eff_state = assumed_state row = { "aggr_tree": tree, "aggr_treestate": timewarp_tree_state, "aggr_state": state, # state disregarding assumptions "aggr_assumed_state": assumed_state, # is None, if there are no assumptions "aggr_effective_state": eff_state, # is assumed_state, if there are assumptions, else real state "aggr_name": node["title"], "aggr_output": eff_state["output"], "aggr_hosts": node["reqhosts"], "aggr_function": node["func"], "aggr_group": html.request.var("aggr_group"), } renderer = bi.FoldableTreeRendererTree( row, omit_root=False, expansion_level=config.user.bi_expansion_level, only_problems=False, lazy=False) tdclass, htmlcode = renderer.css_class(), renderer.render() with html.plugged(): # TODO: SOMETHING IS WRONG IN HERE (used to be the same situation in original code!) # FIXME: WHAT is wrong in here?? html.open_h3() # render icons for back and forth button_back_shown = False button_forth_shown = False if int(these_spans[0]["from"]) == timewarp: html.disabled_icon_button("back_off") button_back_shown = True previous_span = None for span in these_spans: if not button_back_shown and int( span["from"] ) == timewarp and previous_span is not None: html.icon_button( html.makeuri([("timewarp", str(int(previous_span["from"]))) ]), _("Jump one phase back"), "back") button_back_shown = True # Multiple followup spans can have the same "from" time # We only show one forth-arrow with an actual time difference elif not button_forth_shown and previous_span and int( previous_span["from"]) == timewarp and int( span["from"]) != timewarp: html.icon_button( html.makeuri([("timewarp", str(int(span["from"])))]), _("Jump one phase forth"), "forth") button_forth_shown = True previous_span = span if not button_forth_shown: html.disabled_icon_button("forth_off") html.write_text(" ") html.icon_button(html.makeuri([("timewarp", "")]), _("Close Timewarp"), "closetimewarp") html.write_text("%s %s" % (_("Timewarp to "), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timewarp)))) html.close_h3() html.open_table(class_=["data", "table", "timewarp"]) html.open_tr(class_=["data", "odd0"]) html.open_td(class_=tdclass) html.write_html(htmlcode) html.close_td() html.close_tr() html.close_table() timewarpcode += html.drain() # Note: 'spans_by_object' returns two arguments which are used by # all availability views but not by BI. There we have to take # only complete aggregations av_rawdata = availability.spans_by_object(spans, None)[0] av_data = availability.compute_availability("bi", av_rawdata, avoptions) # If we abolish the limit we have to fetch the data again # with changed logrow_limit = 0, which means no limit if has_reached_logrow_limit: text = _( "Your query matched more than %d log entries. " "<b>Note:</b> The shown data does not necessarily reflect the " "matched entries and the result might be incomplete. " ) % avoptions["logrow_limit"] text += html.render_a(_('Repeat query without limit.'), html.makeuri([("_unset_logrow_limit", "1")])) html.show_warning(text) if html.output_format == "csv_export" and config.user.may( "general.csv_export"): _output_csv("bi", av_mode, av_data, avoptions) return html.write(timewarpcode) do_render_availability("bi", av_rawdata, av_data, av_mode, None, avoptions) html.bottom_footer() html.body_end()
def render_availability_page(view, filterheaders): # type: (View, FilterHeaders) -> None config.user.need_permission("general.see_availability") if handle_edit_annotations(): return # We make reports about hosts, services or BI aggregates if "service" in view.datasource.infos: what = "service" elif "aggr_name" in view.datasource.infos: what = "bi" else: what = "host" avoptions = get_availability_options_from_url(what) time_range, range_title = avoptions["range"] # We have two display modes: # - Show availability table (stats) "table" # - Show timeline "timeline" # --> controlled by URL variable "av_mode" av_mode = html.request.get_ascii_input_mandatory("av_mode", "table") if av_mode == "timeline": title = _("Availability Timeline") else: title = _("Availability") # This is combined with the object selection # - Show all objects # - Show one specific object # --> controlled by URL variables "av_site", "av_host" and "av_service" # --> controlled by "av_aggr" in case of BI aggregate title += " - " av_object = None # type: AVObjectSpec if html.request.var("av_host"): av_object = (html.request.get_str_input_mandatory("av_site"), html.request.get_str_input_mandatory("av_host"), html.request.get_unicode_input_mandatory("av_service")) title += av_object[1] if av_object[2]: title += " - " + av_object[2] elif html.request.var("av_aggr"): av_object = (None, None, html.request.get_unicode_input_mandatory("av_aggr")) title += av_object[2] else: title += view_title(view.spec) # Deletion must take place before computation, since it affects the outcome with html.plugged(): handle_delete_annotations() confirmation_html_code = html.drain() # Now compute all data, we need this also for CSV export if not html.has_user_errors(): include_long_output = av_mode == "timeline" \ and "timeline_long_output" in avoptions["labelling"] av_rawdata, has_reached_logrow_limit = availability.get_availability_rawdata( what, view.context, filterheaders, view.only_sites, av_object=av_object, include_output=av_mode == "timeline", include_long_output=include_long_output, avoptions=avoptions) av_data = availability.compute_availability(what, av_rawdata, avoptions) # Do CSV ouput if html.output_format == "csv_export" and config.user.may( "general.csv_export"): _output_csv(what, av_mode, av_data, avoptions) return title += " - " + range_title if display_options.enabled(display_options.H): html.body_start(title, force=True) if display_options.enabled(display_options.T): html.top_heading(title) html.write(confirmation_html_code) # Remove variables for editing annotations, otherwise they will make it into the uris html.request.del_vars("anno_") if html.request.var("filled_in") == "editanno": html.request.del_var("filled_in") if display_options.enabled(display_options.B): html.begin_context_buttons() html.toggle_button( "avoptions", html.has_user_errors(), "painteroptions", _("Configure details of the report"), ) html.context_button( _("Status View"), html.makeuri([("mode", "status")]), "status", ) if config.reporting_available() and config.user.may( "general.reporting"): html.context_button( _("Export as PDF"), html.makeuri([], filename="report_instant.py"), "report", ) if config.user.may("general.csv_export"): html.context_button( _("Export as CSV"), html.makeuri([("output_format", "csv_export")]), "download_csv", ) if av_mode == "timeline" or av_object: html.context_button( _("Availability"), html.makeuri([("av_mode", "availability"), ("av_host", ""), ("av_aggr", "")]), "availability", ) elif not av_object: html.context_button( _("Timeline"), html.makeuri([("av_mode", "timeline")]), "timeline", ) elif av_mode == "timeline" and what != "bi": history_url = availability.history_url_of(av_object, time_range) html.context_button( _("History"), history_url, "history", ) html.end_context_buttons() # Render the avoptions again to get the HTML code, because the HTML vars have changed # above (anno_ and editanno_ has been removed, which must not be part of the form avoptions = render_availability_options(what) if not html.has_user_errors(): # If we abolish the limit we have to fetch the data again # with changed logrow_limit = 0, which means no limit if has_reached_logrow_limit: text = _( "Your query matched more than %d log entries. " "<b>Note:</b> The number of shown rows does not necessarily reflect the " "matched entries and the result might be incomplete. " ) % avoptions["logrow_limit"] text += html.render_a( _('Repeat query without limit.'), html.makeuri([("_unset_logrow_limit", "1"), ("avo_logrow_limit", 0)])) html.show_warning(text) do_render_availability(what, av_rawdata, av_data, av_mode, av_object, avoptions) if display_options.enabled(display_options.Z): html.bottom_footer() if display_options.enabled(display_options.H): html.body_end()
def show_without_timeseries(self): @site_query def query(cls, properties, context): return [ "host_name", "service_check_command", "service_description", "service_perf_data", "service_state" ] col_names, data = query( # pylint: disable=unbalanced-tuple-unpacking self, json.dumps(self.vs_parameters().value_to_json(self._dashlet_spec)), self._dashlet_spec["context"]) row = dict(zip(col_names, data[0])) site = row["site"] host = row["host_name"] service = row["service_description"] metric = self._dashlet_spec.get("metric", "") t_metrics = translate_perf_data(row["service_perf_data"], row["service_check_command"]) chosen_metric = t_metrics.get(metric) if chosen_metric is None: html.show_warning( _("There are no metrics meeting your context filters.")) warning_txt = HTML( _("The given metric \"%s\" could not be found.\ For the selected service \"%s\" you can choose from the following metrics:" % (metric, service))) warning_txt += html.render_ul("".join( [str(html.render_li(m["title"])) for m in t_metrics.values()])) html.show_warning(warning_txt) return svc_url = "view.py?view_name=service&site=%s&host=%s&service=%s" % ( html.urlencode(site), html.urlencode(host), html.urlencode(service)) links = { "site": html.render_a( site, "view.py?view_name=sitehosts&site=%s" % (html.urlencode(site))), "host": html.render_a( host, "view.py?view_name=host&site=%s&host=%s" % (html.urlencode(site), html.urlencode(host))), "service": html.render_a(service, svc_url) } render_options = self._dashlet_spec["render_options"] svc_state = row["service_state"] html.open_div(class_="metric") metric_spec = { "site": site, "host": host, "service": service, "metric": chosen_metric.get("title", metric) } titles = self._get_titles(metric_spec, links, render_options) self._render_metric_content(chosen_metric, render_options, titles, svc_state, svc_url) html.close_div()
def _show_read_only_warning() -> None: if cmk.gui.watolib.read_only.is_enabled(): html.show_warning(cmk.gui.watolib.read_only.message())
def _show_page_user_profile(change_pw): start_async_replication = False if not config.user.id: raise MKUserError(None, _('Not logged in.')) if not config.user.may('general.edit_profile') and not config.user.may( 'general.change_password'): raise MKAuthException( _("You are not allowed to edit your user profile.")) if not config.wato_enabled: raise MKAuthException( _('User profiles can not be edited (WATO is disabled).')) success = None if html.request.has_var('_save') and html.check_transaction(): users = userdb.load_users(lock=True) try: # Profile edit (user options like language etc.) if config.user.may('general.edit_profile'): if not change_pw: set_lang = html.get_checkbox('_set_lang') language = html.request.var('language') # Set the users language if requested if set_lang: if language == '': language = None # Set custom language users[config.user.id]['language'] = language config.user.language = language html.set_language_cookie(language) else: # Remove the customized language if 'language' in users[config.user.id]: del users[config.user.id]['language'] config.user.reset_language() # load the new language cmk.gui.i18n.localize(config.user.language) user = users.get(config.user.id) if config.user.may('general.edit_notifications' ) and user.get("notifications_enabled"): value = forms.get_input( watolib.get_vs_flexible_notifications(), "notification_method") users[config.user.id]["notification_method"] = value # Custom attributes if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): if not attr.permission() or config.user.may( attr.permission()): vs = attr.valuespec() value = vs.from_html_vars('ua_' + name) vs.validate_value(value, "ua_" + name) users[config.user.id][name] = value # Change the password if requested password_changed = False if config.user.may('general.change_password'): cur_password = html.request.var('cur_password') password = html.request.var('password') password2 = html.request.var('password2', '') if change_pw: # Force change pw mode if not cur_password: raise MKUserError( "cur_password", _("You need to provide your current password.")) if not password: raise MKUserError( "password", _("You need to change your password.")) if cur_password == password: raise MKUserError( "password", _("The new password must differ from your current one." )) if cur_password and password: if userdb.hook_login(config.user.id, cur_password) is False: raise MKUserError("cur_password", _("Your old password is wrong.")) if password2 and password != password2: raise MKUserError( "password2", _("The both new passwords do not match.")) watolib.verify_password_policy(password) users[config.user.id]['password'] = hash_password(password) users[config.user.id]['last_pw_change'] = int(time.time()) if change_pw: # Has been changed, remove enforcement flag del users[config.user.id]['enforce_pw_change'] # Increase serial to invalidate old cookies if 'serial' not in users[config.user.id]: users[config.user.id]['serial'] = 1 else: users[config.user.id]['serial'] += 1 password_changed = True # Now, if in distributed environment where users can login to remote sites, # set the trigger for pushing the new auth information to the slave sites # asynchronous if config.user.authorized_login_sites(): start_async_replication = True userdb.save_users(users) if password_changed: # Set the new cookie to prevent logout for the current user login.set_auth_cookie(config.user.id) success = True except MKUserError as e: html.add_user_error(e.varname, e) else: users = userdb.load_users() watolib.init_wato_datastructures(with_wato_lock=True) # When in distributed setup, display the replication dialog instead of the normal # profile edit dialog after changing the password. if start_async_replication: user_profile_async_replication_page() return if change_pw: title = _("Change Password") else: title = _("Edit User Profile") html.header(title) # Rule based notifications: The user currently cannot simply call the according # WATO module due to WATO permission issues. So we cannot show this button # right now. if not change_pw: rulebased_notifications = watolib.load_configuration_settings().get( "enable_rulebased_notifications") if rulebased_notifications and config.user.may( 'general.edit_notifications'): html.begin_context_buttons() url = "wato.py?mode=user_notifications_p" html.context_button(_("Notifications"), url, "notifications") html.end_context_buttons() else: reason = html.request.var('reason') if reason == 'expired': html.p( _('Your password is too old, you need to choose a new password.' )) else: html.p( _('You are required to change your password before proceeding.' )) if success: html.reload_sidebar() if change_pw: html.show_message(_("Your password has been changed.")) raise HTTPRedirect(html.request.var('_origtarget', 'index.py')) else: html.show_message(_("Successfully updated user profile.")) # Ensure theme changes are applied without additional user interaction html.immediate_browser_redirect(0.5, html.makeuri([])) if html.has_user_errors(): html.show_user_errors() user = users.get(config.user.id) if user is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return # Returns true if an attribute is locked and should be read only. Is only # checked when modifying an existing user locked_attributes = userdb.locked_attributes(user.get('connector')) def is_locked(attr): return attr in locked_attributes html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(_("Personal Settings")) if not change_pw: forms.section(_("Name"), simple=True) html.write_text(user.get("alias", config.user.id)) if config.user.may( 'general.change_password') and not is_locked('password'): forms.section(_("Current Password")) html.password_input('cur_password', autocomplete="new-password") forms.section(_("New Password")) html.password_input('password', autocomplete="new-password") forms.section(_("New Password Confirmation")) html.password_input('password2', autocomplete="new-password") if not change_pw and config.user.may('general.edit_profile'): select_language(user) # Let the user configure how he wants to be notified if not rulebased_notifications \ and config.user.may('general.edit_notifications') \ and user.get("notifications_enabled"): forms.section(_("Notifications")) html.help( _("Here you can configure how you want to be notified about host and service problems and " "other monitoring events.")) watolib.get_vs_flexible_notifications().render_input( "notification_method", user.get("notification_method")) if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): vs = attr.valuespec() forms.section(_u(vs.title())) value = user.get(name, vs.default_value()) if not attr.permission() or config.user.may( attr.permission()): vs.render_input("ua_" + name, value) html.help(_u(vs.help())) else: html.write(vs.value_to_text(value)) # Save button forms.end() html.button("_save", _("Save")) html.close_div() html.hidden_fields() html.end_form() html.footer()