def _validate_general_host_attributes(host_attributes, new): # inventory_failed and site are no "real" host_attributes (TODO: Clean this up!) all_host_attribute_names = host_attribute_registry.keys() + [ "inventory_failed", "site" ] for name, value in host_attributes.items(): if name not in all_host_attribute_names: raise MKUserError( None, _("Unknown attribute: %s") % html.attrencode(name)) # For real host attributes validate the values try: attr = watolib.host_attribute(name) except KeyError: attr = None if attr is not None: if attr.needs_validation("host", new): attr.validate_input(value, "") # The site attribute gets an extra check if name == "site" and value not in config.allsites().keys(): raise MKUserError(None, _("Unknown site %s") % html.attrencode(value))
def _render_warnings(self, configuration_warnings): html_code = "<div class=warning>" html_code += "<b>%s</b>" % _("Warnings:") html_code += "<ul>" for domain, warnings in sorted(configuration_warnings.items()): for warning in warnings: html_code += "<li>%s: %s</li>" % \ (html.attrencode(domain), html.attrencode(warning)) html_code += "</ul>" html_code += "</div>" return html_code
def _validate_host_tags(host_tags): for tag_group_id, tag_id in host_tags.items(): for tag_group in config.tags.tag_groups: if tag_group.id == tag_group_id: for grouped_tag in tag_group.tags: if grouped_tag.id == tag_id: break else: raise MKUserError(None, _("Unknown tag %s") % html.attrencode(tag_id)) break else: raise MKUserError(None, _("Unknown tag group %s") % html.attrencode(tag_group_id))
def _show_row_cells(self, table, name, group): table.cell(_("Actions"), css="buttons") edit_url = watolib.folder_preserving_link([("mode", "edit_%s_group" % self.type_name), ("edit", name)]) delete_url = html.makeactionuri([("_delete", name)]) clone_url = watolib.folder_preserving_link([("mode", "edit_%s_group" % self.type_name), ("clone", name)]) html.icon_button(edit_url, _("Properties"), "edit") html.icon_button(clone_url, _("Create a copy of this group"), "clone") html.icon_button(delete_url, _("Delete"), "delete") table.cell(_("Name"), html.attrencode(name)) table.cell(_("Alias"), html.attrencode(group['alias']))
def page_index(): html.write( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n' '<html><head>\n') html.default_html_headers() html.write("""<title>%s</title> </head> <frameset cols="280,*" frameborder="0" framespacing="0" border="0"> <frame src="side.py" name="side" noresize scrolling="no"> <frame src="%s" name="main" noresize> </frameset> </html> """ % (html.attrencode( config.get_page_heading()), html.attrencode(_get_start_url())))
def log_entry(linkinfo, action, message, user_id=None): # Using attrencode here is against our regular rule to do the escaping # at the last possible time: When rendering. But this here is the last # place where we can distinguish between HTML() encapsulated (already) # escaped / allowed HTML and strings to be escaped. message = html.attrencode(message).strip() # TODO: Create a more generic referencing # linkinfo identifies the object operated on. It can be a Host or a Folder # or a text. # linkinfo is either a Folder, or a Host or a hostname or None if hasattr(linkinfo, "linkinfo"): link = linkinfo.linkinfo() else: link = linkinfo write_tokens = ( time.strftime("%s"), link or "-", user_id or config.user.id or "-", action, message.replace("\n", "\\n"), ) # TODO: once we know all of these are unicode, remove this line write_tokens = (t if isinstance(t, unicode) else t.encode("utf-8") for t in write_tokens) store.makedirs(audit_log_path.parent) with audit_log_path.open(mode="a", encoding='utf-8') as f: audit_log_path.chmod(0o660) f.write(u" ".join(write_tokens) + u"\n")
def page_login(): title = _("Check_MK Mobile") mobile_html_head(title) jqm_page_header(title, id_="login") html.div(_("Welcome to Check_MK Mobile."), id_="loginhead") html.begin_form("login", method='POST', add_transid=False) # Keep information about original target URL origtarget = html.request.var('_origtarget', '') if not origtarget and not html.myfile == 'login': origtarget = html.request.requested_url html.hidden_field('_origtarget', html.attrencode(origtarget)) html.text_input("_username", label=_("Username:"******"_password", size=None, label=_("Password:"******"_login", _('Login')) html.set_focus("_username") html.end_form() html.open_div(id_="loginfoot") html.img("themes/classic/images/logo_cmk_small.png", class_="logomk") html.div(HTML( _("© <a target=\"_blank\" href=\"https://checkmk.com\">tribe29 GmbH</a>" )), class_="copyright") jqm_page_footer() mobile_html_foot()
def page_login(): title = _("Check_MK Mobile") mobile_html_head(title) jqm_page_header(title, id_="login") html.div(_("Welcome to Check_MK Mobile."), id_="loginhead") html.begin_form("login", method='POST', add_transid=False) # Keep information about original target URL default_origtarget = "index.py" if html.myfile in ["login", "logout"] else html.makeuri([]) origtarget = html.get_url_input("_origtarget", default_origtarget) html.hidden_field('_origtarget', html.attrencode(origtarget)) html.text_input("_username", label=_("Username:"******"username") html.password_input("_password", size=None, label=_("Password:"******"current-password") html.br() html.button("_login", _('Login')) html.set_focus("_username") html.end_form() html.open_div(id_="loginfoot") html.img("themes/classic/images/logo_cmk_small.png", class_="logomk") html.div(HTML(_("© <a target=\"_blank\" href=\"https://checkmk.com\">tribe29 GmbH</a>")), class_="copyright") html.close_div() # close content-div html.close_div() html.close_div() # close page-div mobile_html_foot()
def _add_change_to_site(self, site_id, change_id, action_name, text, obj, add_user, need_sync, need_restart, domains): # Individual changes may override the domain restart default value if need_restart is None: need_restart = any([d.needs_activation for d in domains]) if need_sync is None: need_sync = any([d.needs_sync for d in domains]) def serialize_object(obj): if obj is None: return None return obj.__class__.__name__, obj.ident() # Using attrencode here is against our regular rule to do the escaping # at the last possible time: When rendering. But this here is the last # place where we can distinguish between HTML() encapsulated (already) # escaped / allowed HTML and strings to be escaped. text = html.attrencode(text) SiteChanges(site_id).save_change({ "id": change_id, "action_name": action_name, "text": "%s" % text, "object": serialize_object(obj), "user_id": config.user.id if add_user else None, "domains": [d.ident for d in domains], "time": time.time(), "need_sync": need_sync, "need_restart": need_restart, })
def page_view(): view_name = html.request.var("view_name") if not view_name: return page_index() view_spec = views.get_permitted_views().get(view_name) if not view_spec: raise MKUserError("view_name", "No view defined with the name '%s'." % view_name) view = views.View(view_name, view_spec) view.row_limit = views.get_limit() view.only_sites = views.get_only_sites() view.user_sorters = views.get_user_sorters() title = views.view_title(view_spec) mobile_html_head(title) painter_options = PainterOptions.get_instance() painter_options.load(view_name) try: view_renderer = MobileViewRenderer(view) views.show_view(view, view_renderer) except Exception as e: logger.exception() if config.debug: raise html.write("ERROR showing view: %s" % html.attrencode(e)) mobile_html_foot()
def _get_api_call(): action = html.request.var('action') for cls in api_call_collection_registry.values(): api_call = cls().get_api_calls().get(action) if api_call: return api_call raise MKUserError(None, "Unknown API action %s" % html.attrencode(action))
def log_entry(linkinfo, action, message, user_id=None): # Using attrencode here is against our regular rule to do the escaping # at the last possible time: When rendering. But this here is the last # place where we can distinguish between HTML() encapsulated (already) # escaped / allowed HTML and strings to be escaped. message = cmk.utils.make_utf8(html.attrencode(message)).strip() # TODO: Create a more generic referencing # linkinfo identifies the object operated on. It can be a Host or a Folder # or a text. # linkinfo is either a Folder, or a Host or a hostname or None if hasattr(linkinfo, "linkinfo"): link = linkinfo.linkinfo() elif linkinfo is None: link = "-" else: link = linkinfo if user_id is None and config.user.id is not None: user_id = config.user.id elif user_id == '': user_id = '-' if user_id: user_id = user_id.encode("utf-8") store.makedirs(os.path.dirname(audit_log_path)) with open(audit_log_path, "ab") as f: os.chmod(f.name, 0o660) f.write("%d %s %s %s %s\n" % (int( time.time()), link, user_id, action, message.replace("\n", "\\n")))
def run(self): self._executed = True try: # Do not merge results that have been gathered on one site for different sites results = list(self.execute()) num_sites = len(set(r.site_id for r in results)) if num_sites > 1: for result in results: result.from_test(self) yield result return # Merge multiple results produced for a single site total_result = ACResult.merge(*list(self.execute())) total_result.from_test(self) yield total_result except Exception: logger.exception("error executing configuration test %s", self.__class__.__name__) result = ACResultCRIT( "<pre>%s</pre>" % _("Failed to execute the test %s: %s") % (html.attrencode( self.__class__.__name__), traceback.format_exc())) result.from_test(self) yield result
def show_crash_report(info): html.h2(_("Crash Report")) html.open_table(class_="data") _crash_row(_("Crash Type"), info["crash_type"], odd=False, legend=True) _crash_row( _("Time"), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(info["time"])), odd=True) _crash_row(_("Operating System"), info["os"], False) if info["crash_type"] == "cma": version_title = _("CMA Version") else: version_title = _("Check_MK Version") _crash_row(version_title, info["version"], True) _crash_row(_("Edition"), info.get("edition", ""), False) _crash_row(_("Core"), info.get("core", ""), True) _crash_row(_("Python Version"), info.get("python_version", _("Unknown")), False) _crash_row( _("Exception"), "%s (%s)" % (info["exc_type"], info["exc_value"]), odd=True, pre=True) _crash_row(_("Traceback"), format_traceback(info["exc_traceback"]), odd=False, pre=True) _crash_row( _("Local Variables"), format_local_vars(info["local_vars"]) if "local_vars" in info else "", odd=True, pre=True) joined_paths = "<br>".join( [html.attrencode(p) for p in info.get("python_paths", [_("Unknown")])]) _crash_row(_("Python Module Paths"), joined_paths, odd=False) html.close_table()
def action(self, cmdtag, spec, row, row_index, num_rows): for s in [0, 1, 2, 3]: statename = html.request.var("_fake_%d" % s) if statename: pluginoutput = html.get_unicode_input("_fake_output").strip() if not pluginoutput: pluginoutput = _("Manually set to %s by %s") % ( html.attrencode(statename), config.user.id) perfdata = html.request.var("_fake_perfdata") if perfdata: pluginoutput += "|" + perfdata if cmdtag == "SVC": cmdtag = "SERVICE" command = "PROCESS_%s_CHECK_RESULT;%s;%s;%s" % ( cmdtag, spec, s, livestatus.lqencode(pluginoutput)) title = _("<b>manually set check results to %s</b> for" ) % html.attrencode(statename) return command, title
def render_messages(self): for msg in notify.get_gui_messages(): if 'gui_hint' in msg['methods']: html.open_div(id_="message-%s" % msg['id'], class_=["popup_msg"]) html.a("x", href="javascript:void(0)", class_=["close"], onclick="cmk.sidebar.message_close(\'%s\')" % msg['id']) html.write_text(msg['text'].replace('\n', '<br>\n')) html.close_div() if 'gui_popup' in msg['methods']: html.javascript('alert(\'%s\'); cmk.sidebar.mark_message_read("%s")' % (html.attrencode(msg['text']).replace('\n', '\\n'), msg['id']))
def _activate_changes(self, request): mode = request.get("mode", "dirty") if request.get("allow_foreign_changes"): allow_foreign_changes = bool( int(request.get("allow_foreign_changes"))) else: allow_foreign_changes = False sites = request.get("sites") changes = watolib.ActivateChanges() changes.load() if changes.has_foreign_changes(): if not config.user.may("wato.activateforeign"): raise MKAuthException( _("You are not allowed to activate changes of other users." )) if not allow_foreign_changes: raise MKAuthException(_("There are changes from other users and foreign changes "\ "are not allowed in this API call.")) if mode == "specific": for site in sites: if site not in config.allsites().keys(): raise MKUserError( None, _("Unknown site %s") % html.attrencode(site)) manager = watolib.ActivateChangesManager() manager.load() if not manager.has_changes(): raise MKUserError(None, _("Currently there are no changes to activate.")) if not sites: sites = manager.dirty_and_active_activation_sites() comment = request.get("comment", "").strip() if comment == "": comment = None manager.start(sites, comment=comment, activate_foreign=allow_foreign_changes) manager.wait_for_completion() return manager.get_state()
def format_plugin_output(output, row=None, shall_escape=True): ok_marker = '<b class="stmark state0">OK</b>' warn_marker = '<b class="stmark state1">WARN</b>' crit_marker = '<b class="stmark state2">CRIT</b>' unknown_marker = '<b class="stmark state3">UNKN</b>' # In case we have a host or service row use the optional custom attribute # ESCAPE_PLUGIN_OUTPUT (set by host / service ruleset) to override the global # setting. if row: custom_vars = row.get("service_custom_variables", row.get("host_custom_variables", {})) if "ESCAPE_PLUGIN_OUTPUT" in custom_vars: shall_escape = custom_vars["ESCAPE_PLUGIN_OUTPUT"] == "1" if shall_escape: output = html.attrencode(output) output = output.replace("(!)", warn_marker) \ .replace("(!!)", crit_marker) \ .replace("(?)", unknown_marker) \ .replace("(.)", ok_marker) if row and "[running on" in output: a = output.index("[running on") e = output.index("]", a) hosts = output[a + 12:e].replace(" ", "").split(",") h = get_host_list_links(row["site"], hosts) output = output[:a] + "running on " + ", ".join(h) + output[e + 1:] if shall_escape: http_url = r"(http[s]?://[A-Za-z0-9\-._~:/?#\[\]@!$&'()*+,;=%]+)" # (?:<A HREF="), (?: target="_blank">)? and endswith(" </A>") is a special # handling for the HTML code produced by check_http when "clickable URL" option is active. output = re.sub( "(?:<A HREF=")?" + http_url + "(?: target="_blank">)?", lambda p: str( html.render_icon_button( p.group(1).replace('"', ''), p.group(1).replace('"', ''), "link")), output) if output.endswith(" </A>"): output = output[:-11] return output
def _push_snapshot_to_site(self): """Calls a remote automation call push-snapshot which is handled by AutomationPushSnapshot()""" site = config.site(self._site_id) url = html.makeuri_contextless( [ ("command", "push-snapshot"), ("secret", site["secret"]), ("siteid", site["id"]), ("debug", config.debug and "1" or ""), ], filename=site["multisiteurl"] + "automation.py", ) response_text = self._upload_file(url, site.get('insecure', False)) try: return ast.literal_eval(response_text) except SyntaxError: raise cmk.gui.watolib.automations.MKAutomationException( _("Garbled automation response: <pre>%s</pre>") % (html.attrencode(response_text)))
def _ajax_switch_masterstate(self): html.set_output_format("text") if not config.user.may("sidesnap.master_control"): return if not html.check_transaction(): return site = html.request.var("site") column = html.request.var("switch") state = int(html.request.var("state")) commands = { ("enable_notifications", 1): "ENABLE_NOTIFICATIONS", ("enable_notifications", 0): "DISABLE_NOTIFICATIONS", ("execute_service_checks", 1): "START_EXECUTING_SVC_CHECKS", ("execute_service_checks", 0): "STOP_EXECUTING_SVC_CHECKS", ("execute_host_checks", 1): "START_EXECUTING_HOST_CHECKS", ("execute_host_checks", 0): "STOP_EXECUTING_HOST_CHECKS", ("enable_flap_detection", 1): "ENABLE_FLAP_DETECTION", ("enable_flap_detection", 0): "DISABLE_FLAP_DETECTION", ("process_performance_data", 1): "ENABLE_PERFORMANCE_DATA", ("process_performance_data", 0): "DISABLE_PERFORMANCE_DATA", ("enable_event_handlers", 1): "ENABLE_EVENT_HANDLERS", ("enable_event_handlers", 0): "DISABLE_EVENT_HANDLERS", } command = commands.get((column, state)) if command: sites.live().command("[%d] %s" % (int(time.time()), command), site) sites.live().set_only_sites([site]) sites.live().query("GET status\nWaitTrigger: program\nWaitTimeout: 10000\nWaitCondition: %s = %d\nColumns: %s\n" % \ (column, state, column)) sites.live().set_only_sites() self.show() else: html.write( _("Command %s/%d not found") % (html.attrencode(column), state))
def page_view(): view_name = html.request.var("view_name") if not view_name: return page_index() view_spec = views.get_permitted_views().get(view_name) if not view_spec: raise MKUserError("view_name", "No view defined with the name '%s'." % view_name) datasource = data_source_registry[view_spec["datasource"]]() context = visuals.get_merged_context( visuals.get_context_from_uri_vars(datasource.infos), view_spec["context"], ) view = views.View(view_name, view_spec, context) view.row_limit = views.get_limit() view.only_sites = views.get_only_sites() view.user_sorters = views.get_user_sorters() title = views.view_title(view_spec) mobile_html_head(title) painter_options = PainterOptions.get_instance() painter_options.load(view_name) try: view_renderer = MobileViewRenderer(view) views.show_view(view, view_renderer) except Exception as e: logger.exception("error showing mobile view") if config.debug: raise html.write("ERROR showing view: %s" % html.attrencode(e)) mobile_html_foot()
def _show_user_list(self): visible_custom_attrs = [ (name, attr) for name, attr in userdb.get_user_attributes() if attr.show_in_table() ] users = userdb.load_users() entries = users.items() html.begin_form("bulk_delete_form", method="POST") roles = userdb.load_roles() timeperiods = watolib.timeperiods.load_timeperiods() contact_groups = load_contact_group_information() with table_element("users", None, empty_text=_("No users are defined yet.")) as table: online_threshold = time.time() - config.user_online_maxage for uid, user in sorted(entries, key=lambda x: x[1].get("alias", x[0]).lower()): table.row() # Checkboxes table.cell(html.render_input("_toggle_group", type_="button", class_="checkgroup", onclick="cmk.selection.toggle_all_rows();", value='X'), sortable=False, css="checkbox") if uid != config.user.id: html.checkbox("_c_user_%s" % base64.b64encode(uid.encode("utf-8"))) user_connection_id = userdb.cleanup_connection_id(user.get('connector')) connection = userdb.get_connection(user_connection_id) # Buttons table.cell(_("Actions"), css="buttons") if connection: # only show edit buttons when the connector is available and enabled edit_url = watolib.folder_preserving_link([("mode", "edit_user"), ("edit", uid)]) html.icon_button(edit_url, _("Properties"), "edit") clone_url = watolib.folder_preserving_link([("mode", "edit_user"), ("clone", uid)]) html.icon_button(clone_url, _("Create a copy of this user"), "clone") delete_url = make_action_link([("mode", "users"), ("_delete", uid)]) html.icon_button(delete_url, _("Delete"), "delete") notifications_url = watolib.folder_preserving_link([("mode", "user_notifications"), ("user", uid)]) if watolib.load_configuration_settings().get("enable_rulebased_notifications"): html.icon_button(notifications_url, _("Custom notification table of this user"), "notifications") # ID table.cell(_("ID"), uid) # Online/Offline if config.save_user_access_times: last_seen = user.get('last_seen', 0) if last_seen >= online_threshold: title = _('Online') img_txt = 'online' elif last_seen != 0: title = _('Offline') img_txt = 'offline' elif last_seen == 0: title = _('Never logged in') img_txt = 'inactive' title += ' (%s %s)' % (render.date(last_seen), render.time_of_day(last_seen)) table.cell(_("Act.")) html.icon(title, img_txt) table.cell(_("Last seen")) if last_seen != 0: html.write_text("%s %s" % (render.date(last_seen), render.time_of_day(last_seen))) else: html.write_text(_("Never logged in")) if cmk.is_managed_edition(): table.cell(_("Customer"), managed.get_customer_name(user)) # Connection if connection: table.cell(_("Connection"), '%s (%s)' % (connection.short_title(), user_connection_id)) locked_attributes = userdb.locked_attributes(user_connection_id) else: table.cell(_("Connection"), "%s (%s) (%s)" % (_("UNKNOWN"), user_connection_id, _("disabled")), css="error") locked_attributes = [] # Authentication if "automation_secret" in user: auth_method = _("Automation") elif user.get("password") or 'password' in locked_attributes: auth_method = _("Password") else: auth_method = "<i>%s</i>" % _("none") table.cell(_("Authentication"), auth_method) table.cell(_("State")) if user.get("locked", False): html.icon(_('The login is currently locked'), 'user_locked') if "disable_notifications" in user and isinstance(user["disable_notifications"], bool): disable_notifications_opts = {"disable": user["disable_notifications"]} else: disable_notifications_opts = user.get("disable_notifications", {}) if disable_notifications_opts.get("disable", False): html.icon(_('Notifications are disabled'), 'notif_disabled') # Full name / Alias table.text_cell(_("Alias"), user.get("alias", "")) # Email table.text_cell(_("Email"), user.get("email", "")) # Roles table.cell(_("Roles")) if user.get("roles", []): role_links = [(watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role)]), roles[role].get("alias")) for role in user["roles"]] html.write_html( HTML(", ").join( html.render_a(alias, href=link) for (link, alias) in role_links)) # contact groups table.cell(_("Contact groups")) cgs = user.get("contactgroups", []) if cgs: cg_aliases = [ contact_groups[c]['alias'] if c in contact_groups else c for c in cgs ] cg_urls = [ watolib.folder_preserving_link([("mode", "edit_contact_group"), ("edit", c)]) for c in cgs ] html.write_html( HTML(", ").join( html.render_a(content, href=url) for (content, url) in zip(cg_aliases, cg_urls))) else: html.i(_("none")) #table.cell(_("Sites")) #html.write(vs_authorized_sites().value_to_text(user.get("authorized_sites", # vs_authorized_sites().default_value()))) # notifications if not watolib.load_configuration_settings().get("enable_rulebased_notifications"): table.cell(_("Notifications")) if not cgs: html.i(_("not a contact")) elif not user.get("notifications_enabled", True): html.write_text(_("disabled")) elif user.get("host_notification_options", "") == "" and \ user.get("service_notification_options", "") == "": html.write_text(_("all events disabled")) else: tp = user.get("notification_period", "24X7") if tp not in timeperiods: tp = tp + _(" (invalid)") elif tp not in watolib.timeperiods.builtin_timeperiods(): url = watolib.folder_preserving_link([("mode", "edit_timeperiod"), ("edit", tp)]) tp = html.render_a(timeperiods[tp].get("alias", tp), href=url) else: tp = timeperiods[tp].get("alias", tp) html.write(tp) # the visible custom attributes for name, attr in visible_custom_attrs: vs = attr.valuespec() table.cell(html.attrencode(_u(vs.title()))) html.write(vs.value_to_text(user.get(name, vs.default_value()))) html.button("_bulk_delete_users", _("Bulk Delete"), "submit", style="margin-top:10px") html.hidden_fields() html.end_form() if not load_contact_group_information(): url = "wato.py?mode=contact_groups" html.open_div(class_="info") html.write( _("Note: you haven't defined any contact groups yet. If you <a href='%s'>" "create some contact groups</a> you can assign users to them und thus " "make them monitoring contacts. Only monitoring contacts can receive " "notifications.") % url) html.write(" you can assign users to them und thus " "make them monitoring contacts. Only monitoring contacts can receive " "notifications.") html.close_div()
def test_htmllib_integration(register_builtin_html): assert type(html.escaper) == htmllib.Escaper assert html.attrencode("") == "" assert html.permissive_attrencode("") == ""
def heading(text): html.write("<h3>%s</h3>\n" % html.attrencode(text))
def render(self, row, cell): return ("", html.attrencode(row["aggr_name"]))
def _render_headers(self, actions_enabled, actions_visible, empty_columns): if self.options["omit_headers"]: return table_id = self.id html.open_tr() first_col = True for nr, (header, css, help_txt, sortable) in enumerate(self.headers): if self.options["omit_empty_columns"] and empty_columns[nr]: continue text = header if help_txt: header = '<span title="%s">%s</span>' % ( html.attrencode(help_txt), header) css_class = "header_%s" % css if css else None if not self.options["sortable"] or not sortable: html.open_th(class_=css_class) else: reverse = 0 sort = html.request.var('_%s_sort' % table_id) if sort: sort_col, sort_reverse = map(int, sort.split(',', 1)) if sort_col == nr: reverse = 1 if sort_reverse == 0 else 0 action_uri = html.makeactionuri([('_%s_sort' % table_id, '%d,%d' % (nr, reverse))]) html.open_th(class_=["sort", css_class], title=_("Sort by %s") % text, onclick="location.href='%s'" % action_uri) # Add the table action link if first_col: first_col = False if actions_enabled: if not header: header = " " # Fixes layout problem with white triangle if actions_visible: state = '0' help_txt = _('Hide table actions') img = 'table_actions_on' else: state = '1' help_txt = _('Display table actions') img = 'table_actions_off' html.open_div(class_=["toggle_actions"]) html.icon_button(html.makeuri([('_%s_actions' % table_id, state)]), help_txt, img, cssclass='toggle_actions') html.open_span() html.write(header) html.close_span() html.close_div() else: html.write(header) else: html.write(header) html.close_th() html.close_tr()
def _transform_builtin_dashboards(): # type: () -> None if 'builtin_dashboards_transformed' in g: return # Only do this once for name, dashboard in builtin_dashboards.items(): # Do not transform dashboards which are already in the new format if 'context' in dashboard: continue # Transform the dashlets for nr, dashlet in enumerate(dashboard['dashlets']): dashlet.setdefault('show_title', True) if dashlet.get('url', '').startswith('dashlet_hoststats') or \ dashlet.get('url', '').startswith('dashlet_servicestats'): # hoststats and servicestats dashlet['type'] = dashlet['url'][8:].split('.', 1)[0] if '?' in dashlet['url']: # Transform old parameters: # wato_folder # host_contact_group # service_contact_group paramstr = dashlet['url'].split('?', 1)[1] dashlet['context'] = {} for key, val in [ p.split('=', 1) for p in paramstr.split('&') ]: if key == 'host_contact_group': dashlet['context']['opthost_contactgroup'] = { 'neg_opthost_contact_group': '', 'opthost_contact_group': val, } elif key == 'service_contact_group': dashlet['context']['optservice_contactgroup'] = { 'neg_optservice_contact_group': '', 'optservice_contact_group': val, } elif key == 'wato_folder': dashlet['context']['wato_folder'] = { 'wato_folder': val, } del dashlet['url'] elif dashlet.get('urlfunc') and not isinstance( dashlet['urlfunc'], str): raise MKGeneralException( _('Unable to transform dashlet %d of dashboard %s: ' 'the dashlet is using "urlfunc" which can not be ' 'converted automatically.') % (nr, name)) elif dashlet.get('url', '') != '' or dashlet.get( 'urlfunc') or dashlet.get('iframe'): # Normal URL based dashlet dashlet['type'] = 'url' if dashlet.get('iframe'): dashlet['url'] = dashlet['iframe'] del dashlet['iframe'] elif dashlet.get('view', '') != '': # Transform views # There might be more than the name in the view definition view_name = dashlet['view'].split('&')[0] # Copy the view definition into the dashlet copy_view_into_dashlet(dashlet, nr, view_name, load_from_all_views=True) del dashlet['view'] else: raise MKGeneralException( _('Unable to transform dashlet %d of dashboard %s. ' 'You will need to migrate it on your own. Definition: %r' ) % (nr, name, html.attrencode(dashlet))) dashlet.setdefault('context', {}) dashlet.setdefault('single_infos', []) # the modification time of builtin dashboards can not be checked as on user specific # dashboards. Set it to 0 to disable the modification chech. dashboard.setdefault('mtime', 0) dashboard.setdefault('show_title', True) if dashboard['title'] is None: dashboard['title'] = _('No title') dashboard['show_title'] = False dashboard.setdefault('single_infos', []) dashboard.setdefault('context', {}) dashboard.setdefault('topic', _('Overview')) dashboard.setdefault('description', dashboard.get('title', '')) g.builtin_dashboards_transformed = True
def _show_output_box(title, content): html.h3(title) html.open_div(class_="log_output") html.write( html.attrencode(content).replace("\n", "<br>").replace(' ', ' ')) html.close_div()
def _show_host_row(self, rendered_hosts, table, hostname, search_text, show_checkboxes, colspan, host_errors, contact_group_names): if search_text and (search_text.lower() not in hostname.lower()): return host = self._folder.host(hostname) rendered_hosts.append(hostname) effective = host.effective_attributes() table.row() # Column with actions (buttons) if show_checkboxes: table.cell(html.render_input( "_toggle_group", type_="button", class_="checkgroup", onclick="cmk.selection.toggle_all_rows();", value='X'), sortable=False, css="checkbox") # Use CSS class "failed" in order to provide information about # selective toggling inventory-failed hosts for Javascript html.input(name="_c_%s" % hostname, type_="checkbox", value=colspan, class_="failed" if host.discovery_failed() else None) html.label("", "_c_%s" % hostname) table.cell(_("Actions"), css="buttons", sortable=False) self._show_host_actions(host) # Hostname with link to details page (edit host) table.cell(_("Hostname")) errors = host_errors.get(hostname, []) + host.validation_errors() if errors: msg = _("Warning: This host has an invalid configuration: ") msg += ", ".join(errors) html.icon(msg, "validation_error") html.nbsp() if host.is_offline(): html.icon(_("This host is disabled"), "disabled") html.nbsp() if host.is_cluster(): html.icon( _("This host is a cluster of %s") % ", ".join(host.cluster_nodes()), "cluster") html.nbsp() html.a(hostname, href=host.edit_url()) # Show attributes for attr in host_attribute_registry.attributes(): if attr.show_in_table(): attrname = attr.name() if attrname in host.attributes(): tdclass, tdcontent = attr.paint( host.attributes()[attrname], hostname) else: tdclass, tdcontent = attr.paint(effective.get(attrname), hostname) tdclass += " inherited" table.cell(attr.title(), html.attrencode(tdcontent), css=tdclass) # Am I authorized? reason = host.reason_why_may_not("read") if not reason: icon = "authok" title = _("You have permission to this host.") else: icon = "autherr" title = html.strip_tags(reason) table.cell(_('Auth'), html.render_icon(icon, title), css="buttons", sortable=False) # Permissions and Contact groups - through complete recursion and inhertance permitted_groups, host_contact_groups, _use_for_services = host.groups( ) table.cell( _("Permissions"), HTML(", ").join([ self._render_contact_group(contact_group_names, g) for g in permitted_groups ])) table.cell( _("Contact Groups"), HTML(", ").join([ self._render_contact_group(contact_group_names, g) for g in host_contact_groups ])) if not config.wato_hide_hosttags: table.cell(_("Tags"), css="tag-ellipsis") tag_groups, show_all_code = self._limit_labels(host.tag_groups()) html.write( cmk.gui.view_utils.render_tag_groups(tag_groups, "host", with_links=False)) html.write(show_all_code) table.cell(_("Explicit labels"), css="tag-ellipsis") labels, show_all_code = self._limit_labels(host.labels()) html.write( cmk.gui.view_utils.render_labels( labels, "host", with_links=False, label_sources={k: "explicit" for k in labels.keys()})) html.write(show_all_code) # Located in folder if self._folder.is_search_folder(): table.cell(_("Folder")) html.a(host.folder().alias_path(), href=host.folder().url())
def _show_test_row(self, table, test_id, test_results_by_site, site_ids): table.row() table.cell(_("Actions"), css="buttons", sortable=False) html.icon_button( None, _("Toggle result details"), "toggle_details", onclick="cmk.wato.toggle_container('test_result_details_%s')" % test_id) worst_result = sorted(test_results_by_site["site_results"].values(), key=lambda result: result.status)[0] # Disabling of test in total is_test_disabled = self._is_test_disabled(test_id) if is_test_disabled: html.icon_button( html.makeactionuri([ ("_do", "enable"), ("_test_id", worst_result.test_id), ]), _("Reenable this test"), "enable_test", ) else: html.icon_button( html.makeactionuri([ ("_do", "disable"), ("_test_id", worst_result.test_id), ]), _("Disable this test"), "disable_test", ) # assume all have the same test meta information (title, help, ...) table.cell(_("Title"), css="title " + "stale" if is_test_disabled else "") html.write_text(test_results_by_site["test"]["title"]) # Now loop all sites to display their results for site_id in site_ids: if is_test_disabled: table.cell(site_id, "") table.cell("", "") continue result = test_results_by_site["site_results"].get(site_id) if result is None: table.cell(site_id, css="state state-1") table.cell("", css="buttons") continue is_acknowledged = self._is_acknowledged(result) if is_acknowledged or result.status == -1: css = "state stale" else: css = "state state%d" % result.status table.cell(site_id, css=css) html.open_div(title=result.text) html.write_text(result.status_name()) html.close_div() table.cell("", css="buttons") if result.status != 0: if is_acknowledged: html.icon_button( html.makeactionuri([ ("_do", "unack"), ("_site_id", result.site_id), ("_status_id", result.status), ("_test_id", result.test_id), ]), _("Unacknowledge this test result for site %s") % site_id, "unacknowledge_test", ) else: html.icon_button( html.makeactionuri([ ("_do", "ack"), ("_site_id", result.site_id), ("_status_id", result.status), ("_test_id", result.test_id), ]), _("Acknowledge this test result for site %s") % site_id, "acknowledge_test", ) else: html.write("") # Add toggleable notitication context table.row(class_="ac_test_details hidden", id_="test_result_details_%s" % test_id) table.cell(colspan=2 + 2 * len(site_ids)) html.write_text(test_results_by_site["test"]["help"]) if not is_test_disabled: html.open_table() for site_id in site_ids: result = test_results_by_site["site_results"].get(site_id) if result is None: continue html.open_tr() html.td(html.attrencode(site_id)) html.td("%s: %s" % (result.status_name(), result.text)) html.close_tr() html.close_table() # This dummy row is needed for not destroying the odd/even row highlighting table.row(class_="hidden")