def page(self): if not self._analyze_sites(): html.show_message( _("Analyze configuration can only be used with the local site and " "distributed WATO slave sites. You currently have no such site configured." )) return results_by_category = self._perform_tests() site_ids = sorted(self._analyze_sites()) for category_name, results_by_test in sorted( results_by_category.items(), key=lambda x: ACTestCategories.title(x[0])): with table_element( title=ACTestCategories.title(category_name), css="data analyze_config", sortable=False, searchable=False, ) as table: for test_id, test_results_by_site in sorted( results_by_test.items(), key=lambda x: x[1]["test"]["title"]): self._show_test_row(table, test_id, test_results_by_site, site_ids)
def do_commands(what: str, rows: Rows) -> bool: confirm_options, title, executor = views.core_command(what, rows[0], 0, len(rows),)[ 1:4 ] # just get confirm_options, title and executor confirm_title = _("Do you really want to %s") % title r = confirm_with_preview(confirm_title, confirm_options) if r is not True: return r is None # Show commands on negative answer count = 0 already_executed: Set[CommandSpec] = set() for nr, row in enumerate(rows): nagios_commands, _confirm_options, title, executor = views.core_command( what, row, nr, len(rows), ) for command in nagios_commands: if command not in already_executed: executor(command, row["site"]) already_executed.add(command) count += 1 if count > 0: html.show_message(_("Successfully sent %d commands.") % count) return True # Show commands again
def do_log_ack(site, host_name, file_name): sites.live().set_auth_domain("action") logs_to_ack = [] if not host_name and not file_name: # all logs on all hosts for this_site, this_host, logs in all_logs(): for int_filename in logs: file_display = form_file_to_ext(int_filename) logs_to_ack.append( (this_site, this_host, int_filename, file_display)) elif host_name and not file_name: # all logs on one host for int_filename in logfiles_of_host(site, host_name): file_display = form_file_to_ext(int_filename) logs_to_ack.append((site, host_name, int_filename, file_display)) elif host_name and file_name: # one log on one host int_filename = form_file_to_int(file_name) logs_to_ack = [(site, host_name, int_filename, form_file_to_ext(int_filename))] else: for this_site, this_host, logs in all_logs(): file_display = form_file_to_ext(file_name) if file_name in logs: logs_to_ack.append( (this_site, this_host, file_name, file_display)) ack_msg = _get_ack_msg(host_name, file_name) ack = request.var("_ack") if not user.may("general.act"): html.h1(_("Permission denied"), class_=["error"]) html.div(_("You are not allowed to acknowledge %s") % ack_msg, class_=["error"]) html.footer() return # filter invalid values if ack != "1": raise MKUserError("_ack", _("Invalid value for ack parameter.")) for this_site, this_host, int_filename, display_name in logs_to_ack: try: acknowledge_logfile(this_site, this_host, int_filename, display_name) except Exception as e: html.show_error( _("The log file <tt>%s</tt> of host <tt>%s</tt> could not be deleted: %s." ) % (display_name, this_host, e)) html.footer() return html.show_message("<b>%s</b><p>%s</p>" % (_("Acknowledged %s") % ack_msg, _("Acknowledged all messages in %s.") % ack_msg)) html.footer()
def page(self): job_status_snapshot = self._job.get_status_snapshot() if job_status_snapshot.is_active(): html.show_message( _('Parent scan currently running in <a href="%s">background</a>.') % self._job.detail_url() ) return self._show_start_form()
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 page(self): user.need_permission("wato.services") job_status_snapshot = self._job.get_status_snapshot() if job_status_snapshot.is_active(): html.show_message( _('Bulk discovery currently running in <a href="%s">background</a>.' ) % self._job.detail_url()) return self._show_start_form()
def page(self): self._options.update(self._get_audit_log_options_from_request()) audit = self._parse_audit_log() if not audit: html.show_message(_("Found no matching entry.")) elif self._options["display"] == "daily": self._display_daily_audit_log(audit) else: self._display_multiple_days_audit_log(audit)
def delete_job(self): job_id = request.var(self.delete_job_var) if not job_id: return job = GUIBackgroundJob(job_id=job_id) if not job.is_available(): return if job.may_delete(): job.delete() self._did_delete_job = True html.show_message(_("Background job has been deleted"))
def page(self) -> None: title = _("Replicate user profile") breadcrumb = make_simple_page_breadcrumb( mega_menu_registry.menu_user(), title) make_header(html, title, breadcrumb, self._page_menu(breadcrumb)) for message in get_flashed_messages(): html.show_message(message) # Now, if in distributed environment where users can login to remote sites, set the trigger for # pushing the new user profile to the remote sites asynchronously user_profile_async_replication_page( back_url=request.get_url_input("back", "user_profile.py"))
def _show_diagnose_output(self): if not request.var("_save"): html.show_message( _( "You can diagnose the connection to a specific host using this dialog. " "You can either test whether your current configuration is still working " "or investigate in which ways a host can be reached. Simply configure the " "connection options you like to try on the right side of the screen and " 'press the "Test" button. The results will be displayed here.' ) ) return if user_errors: html.show_user_errors() return # TODO: Insert any vs_host valuespec validation # These tests can be called with invalid valuespec settings... # TODO: Replace hard coded icon paths with dynamic ones to old or new theme for ident, title in ModeDiagHost.diag_host_tests(): html.h3(title) html.open_table(class_=["data", "test"]) html.open_tr(class_=["data", "odd0"]) html.open_td(class_="icons") html.open_div() html.icon("reload", id_="%s_img" % ident) html.open_a(href="") html.icon( "reload", title=_("Retry this test"), cssclass="retry", id_="%s_retry" % ident ) html.close_a() html.close_div() html.close_td() html.open_td() html.div("", class_="log", id="%s_log" % ident) html.close_td() html.close_tr() html.close_table() html.javascript( "cmk.host_diagnose.start_test(%s, %s, %s)" % ( json.dumps(ident), json.dumps(self._hostname), json.dumps(transactions.fresh_transid()), ) )
def page(self) -> None: title = self._page_title() breadcrumb = self._breadcrumb() make_header(html, 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 stop_job(self): job_id = request.var(self.stop_job_var) if not job_id: return job = GUIBackgroundJob(job_id) if not job.is_available(): return if not job.is_active(): html.show_message( _("No longer able to stop job. Background job just finished.")) return if job.may_stop(): job.stop() self._did_stop_job = True html.show_message(_("Background job has been stopped"))
def page(self) -> None: acktime = request.get_float_input_mandatory("acktime", time.time()) if request.var("_confirm"): _acknowledge_failed_notifications(acktime, time.time()) if user.authorized_login_sites(): title = _("Replicate user profile") breadcrumb = make_simple_page_breadcrumb( mega_menu_registry.menu_monitoring(), title ) make_header(html, title, breadcrumb) for message in get_flashed_messages(): html.show_message(message) user_profile_async_replication_page(back_url="clear_failed_notifications.py") return failed_notifications = load_failed_notifications(before=acktime, after=acknowledged_time()) self._show_page(acktime, failed_notifications) if request.var("_confirm"): html.reload_whole_page()
def page(self) -> cmk.gui.pages.PageResult: breadcrumb = make_simple_page_breadcrumb( mega_menu_registry["help_links"], self._title()) load_werks() werk_table_options = _werk_table_options_from_request() make_header( html, self._title(), breadcrumb, self._page_menu(breadcrumb, werk_table_options), ) for message in get_flashed_messages(): html.show_message(message) handle_acknowledgement() html.open_div(class_="wato") render_werks_table(werk_table_options) html.close_div() html.footer()
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 show_file(site, host_name, file_name): int_filename = form_file_to_int(file_name) title = _("Logfiles of Host %s: %s") % (host_name, int_filename) breadcrumb = _show_file_breadcrumb(host_name, title) make_header( html, title, breadcrumb, _show_file_page_menu(breadcrumb, site, host_name, int_filename)) if request.has_var("_ack") and not request.var("_do_actions") == _("No"): do_log_ack(site, host_name, file_name) return try: log_chunks = parse_file(site, host_name, int_filename, hidecontext=request.var("_hidecontext", "no") == "yes") except Exception as e: if active_config.debug: raise html.show_error(_("Unable to show logfile: <b>%s</b>") % e) html.footer() return if log_chunks is None: html.show_error(_("The logfile does not exist on site.")) html.footer() return if log_chunks == []: html.show_message( _("This logfile contains no unacknowledged messages.")) html.footer() return html.open_div(id_="logwatch") for log in log_chunks: html.open_table(class_="groupheader") html.open_tr() html.td(form_level(log["level"]), class_=form_level(log["level"])) html.td(form_datetime(log["datetime"]), class_="date") html.close_tr() html.close_table() html.open_table(class_=["section"]) for line in log["lines"]: html.open_tr(class_=line["class"]) html.open_td(class_="lines") html.icon_button( analyse_url(site, host_name, int_filename, line["line"]), _("Analyze this line"), "analyze", ) html.write_text(line["line"].replace(" ", " ").replace( "\1", "<br>")) html.close_td() html.close_tr() html.close_table() html.close_div() html.footer()
def _show_configuration_variables(self) -> None: search = self._search at_least_one_painted = False html.open_div(class_="globalvars") for group, config_variables in self.iter_all_configuration_variables(): header_is_painted = False # needed for omitting empty groups for config_variable in config_variables: varname = config_variable.ident() valuespec = config_variable.valuespec() if self._show_only_modified and varname not in self._current_settings: continue help_text = valuespec.help() or "" title_text = valuespec.title() or "" if (search and search not in group.title().lower() and search not in config_variable.domain().ident().lower() and search not in varname and search not in help_text.lower() and search not in title_text.lower()): continue # skip variable when search is performed and nothing matches at_least_one_painted = True if not header_is_painted: # always open headers when searching forms.header(group.title(), isopen=search or self._show_only_modified) header_is_painted = True default_value = self._default_values[varname] edit_url = folder_preserving_link([ ("mode", self.edit_mode_name), ("varname", varname), ("site", request.var("site", "")), ]) title = HTMLWriter.render_a( title_text, href=edit_url, class_="modified" if varname in self._current_settings else None, title=escaping.strip_tags(help_text), ) if varname in self._current_settings: value = self._current_settings[varname] elif varname in self._global_settings: value = self._global_settings[varname] else: value = default_value try: to_text = valuespec.value_to_html(value) except Exception: logger.exception("error converting %r to text", value) to_text = html.render_error( _("Failed to render value: %r") % value) # Is this a simple (single) value or not? change styling in these cases... simple = True if "\n" in to_text or "<td>" in to_text: simple = False forms.section(title, simple=simple) if varname in self._current_settings: modified_cls = ["modified"] value_title: Optional[str] = _( "This option has been modified.") elif varname in self._global_settings: modified_cls = ["modified globally"] value_title = _( "This option has been modified in global settings.") else: modified_cls = [] value_title = None if is_a_checkbox(valuespec): html.open_div(class_=["toggle_switch_container"] + modified_cls + (["on"] if value else [])) html.toggle_switch( enabled=value, help_txt=_("Immediately toggle this setting"), href=makeactionuri(request, transactions, [("_action", "toggle"), ("_varname", varname)]), class_=modified_cls, title=value_title, ) html.close_div() else: html.a(to_text, href=edit_url, class_=modified_cls, title=value_title) if header_is_painted: forms.end() if not at_least_one_painted and search: html.show_message( _("Did not find any global setting matching your search.")) html.close_div()
def _handle_report_form(self, crash_info: CrashInfo) -> ReportSubmitDetails: details: ReportSubmitDetails try: vs = self._vs_crash_report() details = vs.from_html_vars("_report") vs.validate_value(details, "_report") # Make the resulting page execute the crash report post request url_encoded_params = urlencode_vars([ ("name", details["name"]), ("mail", details["mail"]), ( "crashdump", base64.b64encode( _pack_crash_report( self._get_serialized_crash_report())).decode( "ascii"), ), ]) html.open_div(id_="pending_msg", style="display:none") html.show_message(_("Submitting crash report...")) html.close_div() html.open_div(id_="success_msg", style="display:none") html.show_message( _("Your crash report has been submitted (ID: ###ID###). Thanks for your participation, " "it is very important for the quality of Checkmk.<br><br>" "Please note:" "<ul>" "<li>In general we do <i>not</i> respond to crash reports, " "except we need further information from you.</li>" "<li>We read every feedback thoroughly, but this might happen " "not before a couple of weeks or even months have passed and is " "often aligned with our release cycle.</li>" "<li>If you are in need of a quick solution for your problem, then " "we can help you within the scope of professional support. If you " "already have a support contract, then please use your personal " "support email address to send us a mail refering to your crash " "report.<br>If you are interested in the details about support, " 'you find details on <a href="https://checkmk.com/' 'checkmk_support_contract.html" target="_blank">our website</a>.' )) html.close_div() html.open_div(id_="fail_msg", style="display:none") report_url = makeuri_contextless( request, [ ("subject", "Checkmk Crash Report - " + self._get_version()), ], filename="mailto:" + self._get_crash_report_target(), ) html.show_error( _("Failed to send the crash report. Please download it manually and send it " 'to <a href="%s">%s</a>') % (report_url, self._get_crash_report_target())) html.close_div() html.javascript("cmk.transfer.submit_crash_report(%s, %s);" % (json.dumps(active_config.crash_report_url), json.dumps(url_encoded_params))) except MKUserError as e: user_errors.add(e) return details
def _end(self) -> None: if not self.rows and self.options["omit_if_empty"]: return if self.options["output_format"] == "csv": self._write_csv(csv_separator=request.get_str_input_mandatory( "csv_separator", ";")) return container: ContextManager[bool] = nullcontext(False) if self.title: if self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.open_div(class_="foldable_wrapper") container = foldable_container( treename="table", id_=self.id, isopen=self.isopen, indent=False, title=HTMLWriter.render_h3(self.title, class_=["treeangle", "title"]), save_state=self.options["foldable"] == Foldable.FOLDABLE_SAVE_STATE, ) else: html.h3(self.title, class_="table") with container: if self.help: html.help(self.help) if not self.rows: html.div(self.empty_text, class_="info") return # Controls whether or not actions are available for a table rows, actions_visible, search_term = self._evaluate_user_opts() # Apply limit after search / sorting etc. num_rows_unlimited = len(rows) limit = self.limit if limit: # only use rows up to the limit plus the fixed rows limited_rows = [] for index in range(num_rows_unlimited): row = rows[index] if index < limit or isinstance(row, GroupHeader) or row.fixed: limited_rows.append(row) # Display corrected number of rows num_rows_unlimited -= len([ r for r in limited_rows if isinstance(row, GroupHeader) or r.fixed ]) rows = limited_rows # Render header if self.limit_hint is not None: num_rows_unlimited = self.limit_hint if limit and num_rows_unlimited > limit: html.show_message( _("This table is limited to show only %d of %d rows. " 'Click <a href="%s">here</a> to disable the limitation.') % (limit, num_rows_unlimited, makeuri(request, [("limit", "none")]))) self._write_table(rows, num_rows_unlimited, self._show_action_row(), actions_visible, search_term) if self.title and self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.close_div() return
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 active_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 page(self): html.open_div(id_="ldap") html.open_table() html.open_tr() html.open_td() html.begin_form("connection", method="POST") html.prevent_password_auto_completion() vs = self._valuespec() vs.render_input("connection", self._connection_cfg) vs.set_focus("connection") html.hidden_fields() html.end_form() html.close_td() html.open_td(style="padding-left:10px;vertical-align:top") html.h2(_("Diagnostics")) if not request.var("_test") or not self._connection_id: html.show_message( HTML("<p>%s</p><p>%s</p>" % ( _("You can verify the single parts of your ldap configuration using this " "dialog. Simply make your configuration in the form on the left side and " 'hit the "Save & Test" button to execute the tests. After ' "the page reload, you should see the results of the test here." ), _("If you need help during configuration or experience problems, please refer " 'to the <a target="_blank" ' 'href="https://checkmk.com/checkmk_multisite_ldap_integration.html">' "LDAP Documentation</a>."), ))) else: connection = userdb.get_connection(self._connection_id) assert isinstance(connection, LDAPUserConnector) for address in connection.servers(): html.h3("%s: %s" % (_("Server"), address)) with table_element("test", searchable=False) as table: for title, test_func in self._tests(): table.row() try: state, msg = test_func(connection, address) except Exception as e: state = False msg = _("Exception: %s") % e logger.exception("error testing LDAP %s for %s", title, address) if state: img = html.render_icon("success", _("Success")) else: img = html.render_icon("failed", _("Failed")) table.cell(_("Test"), title) table.cell(_("State"), img) table.cell(_("Details"), msg) connection.disconnect() html.close_td() html.close_tr() html.close_table() html.close_div()
def _show_master_control_site( self, site_id: sites.SiteId, site_status_info: Dict[sites.SiteId, List], items: List[Tuple[str, str]], ) -> None: site_state = sites.states().get(site_id) if not site_state: html.show_error(_("Site state is unknown")) return if site_state["state"] == "dead": html.show_error(str(site_state["exception"])) return if site_state["state"] == "disabled": html.show_message(_("Site is disabled")) return if site_state["state"] == "unknown": if site_state.get("exception"): html.show_error(str(site_state["exception"])) else: html.show_error(_("Site state is unknown")) return is_cmc = site_state["program_version"].startswith("Check_MK ") try: site_info = site_status_info[site_id] except KeyError: html.show_error(_("Site state is unknown")) return html.open_table(class_="master_control") for i, (colname, title) in enumerate(items): # Do not show event handlers on Checkmk Micro Core if is_cmc and title == _("Event handlers"): continue if not is_cmc and title == _("Alert handlers"): continue colvalue = site_info[i] url = makeactionuri_contextless( request, transactions, [ ("site", site_id), ("switch", colname), ("state", "%d" % (1 - colvalue)), ], filename="switch_master_state.py", ) onclick = ( "cmk.ajax.get_url('%s', cmk.utils.update_contents, 'snapin_master_control')" % url ) html.open_tr() html.td(title, class_="left") html.open_td() html.toggle_switch( enabled=colvalue, help_txt=_("Switch '%s' to '%s'") % (title, _("off") if colvalue else _("on")), onclick=onclick, ) html.close_td() html.close_tr() html.close_table()
def _activation_msg(self): html.open_div(id_="async_progress_msg") if message := self._get_initial_message(): html.show_message(message)