def display(self) -> None: html.begin_radio_group(horizontal=True) for value, text in [("1", _("up")), ("2", _("down")), ("-1", _("(ignore)"))]: html.radiobutton(self.ident, value, value == "-1", text + " ") html.end_radio_group()
def display(self) -> None: html.text_input(self._varprefix + "name") html.br() html.begin_radio_group(horizontal=True) html.radiobutton(self._varprefix + "match", "exact", True, label=_("exact match")) html.radiobutton(self._varprefix + "match", "regex", False, label=_("regular expression, substring match")) html.end_radio_group() html.br() html.open_span(class_="min_max_row") html.write_text(_("Min. Version: ")) html.text_input(self._varprefix + "version_from", size=9) html.write_text(" ") html.write_text(_("Max. Vers.: ")) html.text_input(self._varprefix + "version_to", size=9) html.close_span() html.br() html.checkbox( self._varprefix + "negate", False, label=_("Negate: find hosts <b>not</b> having this package"))
def display(self): # type: () -> None html.begin_radio_group(horizontal=True) for value, text in [("no", _("used")), ("yes", _("free")), ("", _("(ignore)"))]: html.radiobutton(self.ident, value, value == "", text + " ") html.end_radio_group()
def display(self): current = html.request.var(self.varname) html.begin_radio_group(horizontal=True) for value, text in [("1", _("yes")), ("0", _("no")), ("-1", _("(ignore)"))]: checked = current == value or (current in [None, ""] and int(value) == self.deflt) html.radiobutton(self.varname, value, checked, text + u" ") html.end_radio_group()
def display_filter_radiobuttons(*, varname: str, options: List[Tuple[str, str]], default: str, value: FilterHTTPVariables) -> None: pick = value.get(varname, default) html.begin_radio_group(horizontal=True) for state, text in options: html.radiobutton(varname, state, pick == state, text + " ") html.end_radio_group()
def _rename_tags_after_confirmation(operation): # type: (ABCOperation) -> Union[bool, str] """Handle renaming and deletion of tags Find affected hosts, folders and rules. Remove or fix those rules according the users' wishes. """ repair_mode = html.request.var("_repair") if repair_mode is not None: try: mode = TagCleanupMode(repair_mode) except ValueError: raise MKUserError("_repair", "Invalid mode") if mode == TagCleanupMode.ABORT: raise MKUserError("id_0", _("Aborting change.")) # make attribute unknown to system, important for save() operations if isinstance(operation, OperationRemoveTagGroup): watolib.host_attributes.undeclare_host_tag_attribute( operation.tag_group_id) affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(operation, mode, watolib.Folder.root_folder()) return _("Modified folders: %d, modified hosts: %d, modified rulesets: %d") % \ (len(affected_folders), len(affected_hosts), len(affected_rulesets)) message = u"" affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder()) if affected_folders: message += _("Affected folders with an explicit reference to this tag " "group and that are affected by the change") + ":" with html.plugged(): _show_affected_folders(affected_folders) message += html.drain() if affected_hosts: message += _("Hosts where this tag group is explicitely set " "and that are effected by the change") + ":" with html.plugged(): _show_affected_hosts(affected_hosts) message += html.drain() if affected_rulesets: message += _( "Rulesets that contain rules with references to the changed tags" ) + ":" with html.plugged(): _show_affected_rulesets(affected_rulesets) message += html.drain() if message: wato_html_head(operation.confirm_title()) html.open_div(class_="really") html.h3(_("Your modifications affect some objects")) html.write_text(message) html.br() html.write_text( _("WATO can repair things for you. It can rename tags in folders, host and rules. " "Removed tag groups will be removed from hosts and folders, removed tags will be " "replaced with the default value for the tag group (for hosts and folders). What " "rules concern, you have to decide how to proceed.")) html.begin_form("confirm", method="POST") if affected_rulesets and _is_removing_tags(operation): html.br() html.b( _("Some tags that are used in rules have been removed by you. What " "shall we do with that rules?")) html.open_ul() html.radiobutton( "_repair", "remove", True, _("Just remove the affected tags from the rules.")) html.br() html.radiobutton( "_repair", "delete", False, _("Delete rules containing tags that have been removed, if tag is used in a positive sense. Just remove that tag if it's used negated." )) else: html.open_ul() html.radiobutton("_repair", "repair", True, _("Fix affected folders, hosts and rules.")) html.br() html.radiobutton("_repair", "abort", False, _("Abort your modifications.")) html.close_ul() html.button("_do_confirm", _("Proceed"), "") html.hidden_fields(add_action_vars=True) html.end_form() html.close_div() return False return True
def _show_start_form(self): html.begin_form("parentscan", method="POST") html.hidden_fields() # Mode of action html.open_p() if not self._complete_folder: num_selected = len(get_hosts_from_checkboxes()) html.write_text( _("You have selected <b>%d</b> hosts for parent scan. ") % num_selected) html.p( _("The parent scan will try to detect the last gateway " "on layer 3 (IP) before a host. This will be done by " "calling <tt>traceroute</tt>. If a gateway is found by " "that way and its IP address belongs to one of your " "monitored hosts, that host will be used as the hosts " "parent. If no such host exists, an artifical ping-only " "gateway host will be created if you have not disabled " "this feature.")) forms.header(_("Settings for Parent Scan")) self._settings = config.user.load_file( "parentscan", { "where": "subfolder", "alias": _("Created by parent scan"), "recurse": True, "select": "noexplicit", "timeout": 8, "probes": 2, "ping_probes": 5, "max_ttl": 10, "force_explicit": False, }) # Selection forms.section(_("Selection")) if self._complete_folder: html.checkbox("recurse", self._settings["recurse"], label=_("Include all subfolders")) html.br() html.radiobutton( "select", "noexplicit", self._settings["select"] == "noexplicit", _("Skip hosts with explicit parent definitions (even if empty)") + "<br>") html.radiobutton( "select", "no", self._settings["select"] == "no", _("Skip hosts hosts with non-empty parents (also if inherited)") + "<br>") html.radiobutton("select", "ignore", self._settings["select"] == "ignore", _("Scan all hosts") + "<br>") # Performance forms.section(_("Performance")) html.open_table() html.open_tr() html.open_td() html.write_text(_("Timeout for responses") + ":") html.close_td() html.open_td() html.number_input("timeout", self._settings["timeout"], size=2) html.write_text(_("sec")) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Number of probes per hop") + ":") html.close_td() html.open_td() html.number_input("probes", self._settings["probes"], size=2) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Maximum distance (TTL) to gateway") + ":") html.close_td() html.open_td() html.number_input("max_ttl", self._settings["max_ttl"], size=2) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Number of PING probes") + ":") html.help( _("After a gateway has been found, Check_MK checks if it is reachable " "via PING. If not, it is skipped and the next gateway nearer to the " "monitoring core is being tried. You can disable this check by setting " "the number of PING probes to 0.")) html.close_td() html.open_td() html.number_input("ping_probes", self._settings.get("ping_probes", 5), size=2) html.close_td() html.close_tr() html.close_table() # Configuring parent forms.section(_("Configuration")) html.checkbox( "force_explicit", self._settings["force_explicit"], label= _("Force explicit setting for parents even if setting matches that of the folder" )) # Gateway creation forms.section(_("Creation of gateway hosts")) html.write_text(_("Create gateway hosts in")) html.open_ul() html.radiobutton( "where", "subfolder", self._settings["where"] == "subfolder", _("in the subfolder <b>%s/Parents</b>") % watolib.Folder.current_disk_folder().title()) html.br() html.radiobutton( "where", "here", self._settings["where"] == "here", _("directly in the folder <b>%s</b>") % watolib.Folder.current_disk_folder().title()) html.br() html.radiobutton("where", "there", self._settings["where"] == "there", _("in the same folder as the host")) html.br() html.radiobutton("where", "nowhere", self._settings["where"] == "nowhere", _("do not create gateway hosts")) html.close_ul() html.write_text(_("Alias for created gateway hosts") + ": ") html.text_input("alias", self._settings["alias"]) forms.end() # Start button html.button("_start", _("Start")) html.hidden_fields() html.end_form()
def page(self): # Let exceptions from loading notification scripts happen now watolib.load_notification_scripts() html.begin_form("user", method="POST") html.prevent_password_auto_completion() forms.header(_("Identity")) # ID forms.section(_("Username"), simple=not self._is_new_user) if self._is_new_user: vs_user_id = UserID(allow_empty=False) else: vs_user_id = FixedValue(self._user_id) vs_user_id.render_input("user_id", self._user_id) def lockable_input(name, dflt): if not self._is_locked(name): html.text_input(name, self._user.get(name, dflt), size=50) else: html.write_text(self._user.get(name, dflt)) html.hidden_field(name, self._user.get(name, dflt)) # Full name forms.section(_("Full name")) lockable_input('alias', self._user_id) html.help(_("Full name or alias of the user")) # Email address forms.section(_("Email address")) email = self._user.get("email", "") if not self._is_locked("email"): EmailAddressUnicode().render_input("email", email) else: html.write_text(email) html.hidden_field("email", email) html.help( _("The email address is optional and is needed " "if the user is a monitoring contact and receives notifications " "via Email.")) forms.section(_("Pager address")) lockable_input('pager', '') html.help(_("The pager address is optional ")) if cmk.is_managed_edition(): forms.section(self._vs_customer.title()) self._vs_customer.render_input("customer", managed.get_customer_id(self._user)) html.help(self._vs_customer.help()) vs_sites = self._vs_sites() forms.section(vs_sites.title()) authorized_sites = self._user.get("authorized_sites", vs_sites.default_value()) if not self._is_locked("authorized_sites"): vs_sites.render_input("authorized_sites", authorized_sites) else: html.write_html(vs_sites.value_to_text(authorized_sites)) html.help(vs_sites.help()) self._show_custom_user_attributes('ident') forms.header(_("Security")) forms.section(_("Authentication")) is_automation = self._user.get("automation_secret", None) is not None html.radiobutton("authmethod", "password", not is_automation, _("Normal user login with password")) html.open_ul() html.open_table() html.open_tr() html.td(_("password:"******"_password_" + self._pw_suffix(), autocomplete="new-password") html.close_td() html.close_tr() html.open_tr() html.td(_("repeat:")) html.open_td() html.password_input("_password2_" + self._pw_suffix(), autocomplete="new-password") html.write_text(" (%s)" % _("optional")) html.close_td() html.close_tr() html.open_tr() html.td("%s:" % _("Enforce change")) html.open_td() # Only make password enforcement selection possible when user is allowed to change the PW if self._is_new_user or config.user_may(self._user_id, 'general.edit_profile') and config.user_may( self._user_id, 'general.change_password'): html.checkbox("enforce_pw_change", self._user.get("enforce_pw_change", False), label=_("Change password at next login or access")) else: html.write_text( _("Not permitted to change the password. Change can not be enforced.")) else: html.i(_('The password can not be changed (It is locked by the user connector).')) html.hidden_field('_password', '') html.hidden_field('_password2', '') html.close_td() html.close_tr() html.close_table() html.close_ul() html.radiobutton("authmethod", "secret", is_automation, _("Automation secret for machine accounts")) html.open_ul() html.text_input("_auth_secret", self._user.get("automation_secret", ""), size=30, id_="automation_secret") html.write_text(" ") html.open_b(style=["position: relative", "top: 4px;"]) html.write(" ") html.icon_button("javascript:cmk.wato.randomize_secret('automation_secret', 20);", _("Create random secret"), "random") html.close_b() html.close_ul() html.help( _("If you want the user to be able to login " "then specify a password here. Users without a login make sense " "if they are monitoring contacts that are just used for " "notifications. The repetition of the password is optional. " "<br>For accounts used by automation processes (such as fetching " "data from views for further procession), set the method to " "<u>secret</u>. The secret will be stored in a local file. Processes " "with read access to that file will be able to use Multisite as " "a webservice without any further configuration.")) # Locking forms.section(_("Disable password"), simple=True) if not self._is_locked('locked'): html.checkbox("locked", self._user.get("locked", False), label=_("disable the login to this account")) else: html.write_text( _('Login disabled') if self._user.get("locked", False) else _('Login possible')) html.hidden_field('locked', '1' if self._user.get("locked", False) else '') html.help( _("Disabling the password will prevent a user from logging in while " "retaining the original password. Notifications are not affected " "by this setting.")) forms.section(_("Idle timeout")) idle_timeout = self._user.get("idle_timeout") if not self._is_locked("idle_timeout"): watolib.get_vs_user_idle_timeout().render_input("idle_timeout", idle_timeout) else: html.write_text(idle_timeout) html.hidden_field("idle_timeout", idle_timeout) # Roles forms.section(_("Roles")) entries = self._roles.items() entries.sort(key=lambda x: (x[1]["alias"], x[0])) is_member_of_at_least_one = False for role_id, role in entries: if not self._is_locked("roles"): html.checkbox("role_" + role_id, role_id in self._user.get("roles", [])) url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)]) html.a(role["alias"], href=url) html.br() else: is_member = role_id in self._user.get("roles", []) if is_member: is_member_of_at_least_one = True url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)]) html.a(role["alias"], href=url) html.br() html.hidden_field("role_" + role_id, '1' if is_member else '') if self._is_locked('roles') and not is_member_of_at_least_one: html.i(_('No roles assigned.')) self._show_custom_user_attributes('security') # Contact groups forms.header(_("Contact Groups"), isopen=False) forms.section() groups_page_url = watolib.folder_preserving_link([("mode", "contact_groups")]) group_assign_url = watolib.folder_preserving_link([("mode", "rulesets"), ("group", "grouping")]) if not self._contact_groups: html.write( _("Please first create some <a href='%s'>contact groups</a>") % groups_page_url) else: entries = sorted([(group['alias'] or c, c) for c, group in self._contact_groups.items() ]) is_member_of_at_least_one = False for alias, gid in entries: is_member = gid in self._user.get("contactgroups", []) if not self._is_locked('contactgroups'): html.checkbox("cg_" + gid, gid in self._user.get("contactgroups", [])) else: if is_member: is_member_of_at_least_one = True html.hidden_field("cg_" + gid, '1' if is_member else '') if not self._is_locked('contactgroups') or is_member: url = watolib.folder_preserving_link([("mode", "edit_contact_group"), ("edit", gid)]) html.a(alias, href=url) html.br() if self._is_locked('contactgroups') and not is_member_of_at_least_one: html.i(_('No contact groups assigned.')) html.help( _("Contact groups are used to assign monitoring " "objects to users. If you haven't defined any contact groups yet, " "then first <a href='%s'>do so</a>. Hosts and services can be " "assigned to contact groups using <a href='%s'>rules</a>.<br><br>" "If you do not put the user into any contact group " "then no monitoring contact will be created for the user.") % (groups_page_url, group_assign_url)) forms.header(_("Notifications"), isopen=False) if not self._rbn_enabled(): forms.section(_("Enabling"), simple=True) html.checkbox("notifications_enabled", self._user.get("notifications_enabled", False), label=_("enable notifications")) html.help( _("Notifications are sent out " "when the status of a host or service changes.")) # Notification period forms.section(_("Notification time period")) choices = [(id_, "%s" % (tp["alias"])) for (id_, tp) in self._timeperiods.items()] html.dropdown("notification_period", choices, deflt=self._user.get("notification_period"), ordered=True) html.help( _("Only during this time period the " "user will get notifications about host or service alerts.")) # Notification options notification_option_names = { # defined here: _() must be executed always! "host": { "d": _("Host goes down"), "u": _("Host gets unreachble"), "r": _("Host goes up again"), }, "service": { "w": _("Service goes into warning state"), "u": _("Service goes into unknown state"), "c": _("Service goes into critical state"), "r": _("Service recovers to OK"), }, "both": { "f": _("Start or end of flapping state"), "s": _("Start or end of a scheduled downtime"), } } forms.section(_("Notification Options")) for title, what, opts in [(_("Host events"), "host", "durfs"), (_("Service events"), "service", "wucrfs")]: html.write_text("%s:" % title) html.open_ul() user_opts = self._user.get(what + "_notification_options", opts) for opt in opts: opt_name = notification_option_names[what].get( opt, notification_option_names["both"].get(opt)) html.checkbox(what + "_" + opt, opt in user_opts, label=opt_name) html.br() html.close_ul() html.help( _("Here you specify which types of alerts " "will be notified to this contact. Note: these settings will only be saved " "and used if the user is member of a contact group.")) forms.section(_("Notification Method")) watolib.get_vs_flexible_notifications().render_input( "notification_method", self._user.get("notification_method")) else: forms.section(_("Fallback notifications"), simple=True) html.checkbox("fallback_contact", self._user.get("fallback_contact", False), label=_("Receive fallback notifications")) html.help( _("In case none of your notification rules handles a certain event a notification " "will be sent to this contact. This makes sure that in that case at least <i>someone</i> " "gets notified. Furthermore this contact will be used for notifications to any host or service " "that is not known to the monitoring. This can happen when you forward notifications " "from the Event Console.<br><br>Notification fallback can also configured in the global " "setting <a href=\"wato.py?mode=edit_configvar&varname=notification_fallback_email\">" "Fallback email address for notifications</a>.")) self._show_custom_user_attributes('notify') forms.header(_("Personal Settings"), isopen=False) select_language(self._user) self._show_custom_user_attributes('personal') # Later we could add custom macros here, which then could be used # for notifications. On the other hand, if we implement some check_mk # --notify, we could directly access the data in the account with the need # to store values in the monitoring core. We'll see what future brings. forms.end() html.button("save", _("Save")) if self._is_new_user: html.set_focus("user_id") else: html.set_focus("alias") html.hidden_fields() html.end_form()
def _rename_tags_after_confirmation(tag_id, operations): """Handle renaming and deletion of tags Find affected hosts, folders and rules. Remove or fix those rules according the the users' wishes. In case auf auxiliary tags the tag_id is None. In other cases it is the id of the tag group currently being edited. """ mode = html.request.var("_repair") if mode == "abort": raise MKUserError("id_0", _("Aborting change.")) elif mode: # make attribute unknown to system, important for save() operations if tag_id and isinstance(operations, list): watolib.host_attributes.undeclare_host_tag_attribute(tag_id) affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(tag_id, operations, mode, watolib.Folder.root_folder()) return _("Modified folders: %d, modified hosts: %d, modified rulesets: %d") % \ (len(affected_folders), len(affected_hosts), len(affected_rulesets)) message = "" affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(tag_id, operations, "check", watolib.Folder.root_folder()) if affected_folders: message += _("Affected folders with an explicit reference to this tag " "group and that are affected by the change") + ":<ul>" for folder in affected_folders: message += '<li><a href="%s">%s</a></li>' % (folder.edit_url(), folder.alias_path()) message += "</ul>" if affected_hosts: message += _("Hosts where this tag group is explicitely set " "and that are effected by the change") + ":<ul><li>" for nr, host in enumerate(affected_hosts): if nr > 20: message += "... (%d more)" % (len(affected_hosts) - 20) break elif nr > 0: message += ", " message += '<a href="%s">%s</a>' % (host.edit_url(), host.name()) message += "</li></ul>" if affected_rulesets: message += _("Rulesets that contain rules with references to the changed tags") + ":<ul>" for ruleset in affected_rulesets: message += '<li><a href="%s">%s</a></li>' % (watolib.folder_preserving_link( [("mode", "edit_ruleset"), ("varname", ruleset.name)]), ruleset.title()) message += "</ul>" if not message and isinstance(operations, tuple): # deletion of unused tag group html.open_div(class_="really") html.begin_form("confirm") html.write_text(_("Please confirm the deletion of the tag group.")) html.button("_abort", _("Abort")) html.button("_do_confirm", _("Proceed")) html.hidden_fields(add_action_vars=True) html.end_form() html.close_div() elif message: if isinstance(operations, list): wato_html_head(_("Confirm tag deletion")) else: wato_html_head(_("Confirm tag modifications")) html.open_div(class_="really") html.h3(_("Your modifications affect some objects")) html.write_text(message) html.br() html.write_text( _("WATO can repair things for you. It can rename tags in folders, host and rules. " "Removed tag groups will be removed from hosts and folders, removed tags will be " "replaced with the default value for the tag group (for hosts and folders). What " "rules concern, you have to decide how to proceed.")) html.begin_form("confirm") # Check if operations contains removal if isinstance(operations, list): have_removal = True else: have_removal = False for new_val in operations.values(): if not new_val: have_removal = True break if affected_rulesets and have_removal: html.br() html.b( _("Some tags that are used in rules have been removed by you. What " "shall we do with that rules?")) html.open_ul() html.radiobutton("_repair", "remove", True, _("Just remove the affected tags from the rules.")) html.br() html.radiobutton( "_repair", "delete", False, _("Delete rules containing tags that have been removed, if tag is used in a positive sense. Just remove that tag if it's used negated." )) else: html.open_ul() html.radiobutton("_repair", "repair", True, _("Fix affected folders, hosts and rules.")) html.br() html.radiobutton("_repair", "abort", False, _("Abort your modifications.")) html.close_ul() html.button("_do_confirm", _("Proceed"), "") html.hidden_fields(add_action_vars=True) html.end_form() html.close_div() return False return True