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 filter_table(self, context: VisualContext, rows: Rows) -> Rows: from_value = utils.saveint(request.var(self.ident + "_from")) to_value = utils.saveint(request.var(self.ident + "_to")) if not from_value and not to_value: return rows newrows = [] for row in rows: value = row.get(self.ident, None) if value is not None: if from_value and value < from_value: continue if to_value and value > to_value: continue newrows.append(row) return newrows
def needs_validation(self, for_what: str, new: bool) -> bool: """Check whether this attribute needs to be validated at all Attributes might be permanently hidden (show_in_form = False) or dynamically hidden by the depends_on_tags, editable features""" if not self.is_visible(for_what, new): return False if not html: return True return request.var("attr_display_%s" % self.name(), "1") == "1"
def _get_host_info_from_row(self, row, row_num): host_name = None attributes: Dict[str, str] = {} for col_num, value in enumerate(row): if not value: continue attribute = request.var("attribute_%d" % col_num) if attribute == "host_name": Hostname().validate_value(value, "host") host_name = value elif attribute and attribute != "-": if attribute in attributes: raise MKUserError( None, _('The attribute "%s" is assigned to multiple columns. ' "You can not populate one attribute from multiple columns. " "The column to attribute associations need to be unique." ) % attribute, ) attr = host_attribute_registry[attribute]() # TODO: The value handling here is incorrect. The correct way would be to use the # host attributes from_html_vars and validate_input, just like collect_attributes() # from cmk/gui/watolib/host_attributes.py is doing it. # The problem here is that we get the value in a different way (from row instead of # HTTP request vars) which from_html_vars can not work with. if attribute == "alias": attributes[attribute] = value else: if not value.isascii(): raise MKUserError( None, _("Non-ASCII characters are not allowed in the " 'attribute "%s".') % attribute, ) try: attr.validate_input(value, "") except MKUserError as e: raise MKUserError( None, _("Invalid value in column %d (%s) of row %d: %s") % (col_num, attribute, row_num, e), ) attributes[attribute] = value if host_name is None: raise MKUserError( None, _("The host name attribute needs to be assigned to a column.")) return host_name, attributes
def display(self): current = 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 _get_hostnames_from_filters(self) -> Set[HostName]: # Determine hosts from filters filter_headers = self._get_filter_headers() query = "GET hosts\nColumns: name" if filter_headers: query += "\n%s" % filter_headers with sites.only_sites(request.var("site")): return {HostName(x[0]) for x in sites.live().query(query)}
def ajax_message_read(): response.set_content_type("application/json") try: message.delete_gui_message(request.var("id")) html.write_text("OK") except Exception: if config.debug: raise html.write_text("ERROR")
def action(self) -> ActionResult: if not transactions.transaction_valid(): return redirect(mode_url("folder")) attributes = watolib.collect_attributes(self._host_type_name(), new=True) cluster_nodes = self._get_cluster_nodes() hostname = request.get_ascii_input_mandatory("host") Hostname().validate_value(hostname, "host") folder = watolib.Folder.current() if transactions.check_transaction(): folder.create_hosts([(hostname, attributes, cluster_nodes)]) self._host = folder.host(hostname) inventory_url = watolib.folder_preserving_link([ ("mode", "inventory"), ("host", self._host.name()), ("_scan", "1"), ]) create_msg = (None if self._host.is_ping_host() else ( _("Successfully created the host. Now you should do a " '<a href="%s">service discovery</a> in order to auto-configure ' "all services to be checked on this host.") % inventory_url)) if request.var("services"): raise redirect(inventory_url) if request.var("diag_host"): if create_msg: flash(create_msg) return redirect( mode_url("diag_host", folder=folder.path(), host=self._host.name(), _try="1")) if create_msg: flash(create_msg) return redirect(mode_url("folder", folder=folder.path()))
def action(self) -> ActionResult: if transactions.transaction_valid(): if request.has_var("_do_upload"): self._upload_csv_file() csv_reader = self._open_csv_file() if request.var("_do_import"): return self._import(csv_reader) return None
def action(self) -> ActionResult: folder = watolib.Folder.current() if not transactions.check_transaction(): return redirect(mode_url("folder", folder=folder.path())) if request.var("_update_dns_cache") and self._should_use_dns_cache(): user.need_permission("wato.update_dns_cache") update_dns_cache_result = update_dns_cache(self._host.site_id()) infotext = ( _("Successfully updated IP addresses of %d hosts.") % update_dns_cache_result.n_updated ) if update_dns_cache_result.failed_hosts: infotext += "<br><br><b>Hostnames failed to lookup:</b> " + ", ".join( ["<tt>%s</tt>" % h for h in update_dns_cache_result.failed_hosts] ) flash(infotext) return None if request.var("delete"): # Delete this host folder.delete_hosts([self._host.name()]) return redirect(mode_url("folder", folder=folder.path())) attributes = watolib.collect_attributes( "host" if not self._is_cluster() else "cluster", new=False ) host = watolib.Host.host(self._host.name()) if host is None: flash(f"Host {self._host.name()} could not be found.") return None host.edit(attributes, self._get_cluster_nodes()) self._host = folder.load_host(self._host.name()) if request.var("_save"): return redirect(mode_url("inventory", folder=folder.path(), host=self._host.name())) if request.var("diag_host"): return redirect( mode_url( "diag_host", folder=folder.path(), host=self._host.name(), _start_on_load="1" ) ) return redirect(mode_url("folder", folder=folder.path()))
def ajax_render_tree(): aggr_group = request.get_str_input("group") aggr_title = request.get_str_input("title") omit_root = bool(request.var("omit_root")) only_problems = bool(request.var("only_problems")) rows = [] bi_manager = BIManager() bi_manager.status_fetcher.set_assumed_states(user.bi_assumptions) aggregation_id = request.get_str_input_mandatory("aggregation_id") bi_aggregation_filter = BIAggregationFilter( [], [], [aggregation_id], [aggr_title] if aggr_title is not None else [], [aggr_group] if aggr_group is not None else [], [], ) rows = bi_manager.computer.compute_legacy_result_for_filter( bi_aggregation_filter) # TODO: Cleanup the renderer to use a class registry for lookup renderer_class_name = request.var("renderer") if renderer_class_name == "FoldableTreeRendererTree": renderer_cls: Type[ABCFoldableTreeRenderer] = FoldableTreeRendererTree elif renderer_class_name == "FoldableTreeRendererBoxes": renderer_cls = FoldableTreeRendererBoxes elif renderer_class_name == "FoldableTreeRendererBottomUp": renderer_cls = FoldableTreeRendererBottomUp elif renderer_class_name == "FoldableTreeRendererTopDown": renderer_cls = FoldableTreeRendererTopDown else: raise NotImplementedError() renderer = renderer_cls( rows[0], omit_root=omit_root, expansion_level=user.bi_expansion_level, only_problems=only_problems, lazy=False, ) html.write_html(renderer.render())
def filter_table(self, context: VisualContext, rows: Rows) -> Rows: current = request.var(self.ident) if current not in ("1", "2"): return rows new_rows = [] for row in rows: admin_status = str(row["invinterface_admin_status"]) if admin_status == current: new_rows.append(row) return new_rows
def ajax_save_treestate(): path_id = request.get_unicode_input_mandatory("path") current_ex_level_str, path = path_id.split(":", 1) current_ex_level = int(current_ex_level_str) if config.user.bi_expansion_level != current_ex_level: config.user.set_tree_states('bi', {}) config.user.set_tree_state('bi', path, request.var("state") == "open") config.user.save_tree_states() config.user.bi_expansion_level = current_ex_level
def display(self) -> None: html.write_text(_("From: ")) htmlvar = self.htmlvars[0] current_value = request.var(htmlvar, "") html.text_input(htmlvar, default_value=str(current_value), size=8, cssclass="number") if self._unit: html.write_text(" %s" % self._unit) html.write_text(" " + _("To: ")) htmlvar = self.htmlvars[1] current_value = request.var(htmlvar, "") html.text_input(htmlvar, default_value=str(current_value), size=8, cssclass="number") if self._unit: html.write_text(" %s" % self._unit)
def page_show(): site = request.var("site") # optional site hint host_name = request.var("host", "") file_name = request.get_unicode_input("file", "") # Fix problem when URL is missing certain illegal characters try: file_name = form_file_to_ext( find_matching_logfile(site, host_name, form_file_to_int(file_name))) except livestatus.MKLivestatusNotFoundError: pass # host_name log dir does not exist if not host_name: show_log_list() return if file_name: show_file(site, host_name, file_name) else: show_host_log_list(site, host_name)
def ajax_save_treestate(): path_id = request.get_str_input_mandatory("path") current_ex_level_str, path = path_id.split(":", 1) current_ex_level = int(current_ex_level_str) if user.bi_expansion_level != current_ex_level: user.set_tree_states("bi", {}) user.set_tree_state("bi", path, request.var("state") == "open") user.save_tree_states() user.bi_expansion_level = current_ex_level
def _from_vars(self): self._start = bool(request.var("_start")) # 'all' not set -> only scan checked hosts in current folder, no recursion # otherwise: all host in this folder, maybe recursively self._all = bool(request.var("all")) self._complete_folder = self._all # Ignored during initial form display self._settings = ParentScanSettings( where=request.get_ascii_input_mandatory("where", "subfolder"), alias=request.get_unicode_input_mandatory("alias", "").strip(), recurse=html.get_checkbox("recurse") or False, select=request.get_ascii_input_mandatory("select", "noexplicit"), timeout=request.get_integer_input_mandatory("timeout", 8), probes=request.get_integer_input_mandatory("probes", 2), max_ttl=request.get_integer_input_mandatory("max_ttl", 10), force_explicit=html.get_checkbox("force_explicit") or False, ping_probes=request.get_integer_input_mandatory("ping_probes", 5), ) self._job = ParentScanBackgroundJob()
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. watolib.add_change( "changes-discarded", msg, domains=watolib.ABCConfigDomain.enabled_domains(), need_restart=True, ) self._extract_snapshot(file_to_restore) activate_changes.execute_activate_changes([ d.get_domain_request([]) for d in watolib.ABCConfigDomain.enabled_domains() ]) for site_id in activation_sites(): self.confirm_site_changes(site_id) build_index_background() html.header( 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 _ajax_tag_tree(self): response.set_content_type("application/json") self._load() new_tree = request.var("tree_id") if new_tree not in self._trees: raise MKUserError("conf", _("This virtual host tree does not exist.")) self._current_tree_id = new_tree self._save_user_settings() response.set_data("OK")
def action(self) -> ActionResult: if not transactions.check_transaction(): return None if request.var('_try'): try: self._validate_diag_html_vars() except MKUserError as e: user_errors.add(e) return None if request.var('_save'): # Save the ipaddress and/or community vs_host = self._vs_host() new = vs_host.from_html_vars('vs_host') vs_host.validate_value(new, 'vs_host') # If both snmp types have credentials set - snmpv3 takes precedence return_message = [] if "ipaddress" in new: return_message.append(_("IP address")) if "snmp_v3_credentials" in new: if "snmp_community" in new: return_message.append( _("SNMPv3 credentials (SNMPv2 community was discarded)" )) else: return_message.append(_("SNMPv3 credentials")) new["snmp_community"] = new["snmp_v3_credentials"] elif "snmp_community" in new: return_message.append(_("SNMP credentials")) self._host.update_attributes(new) flash(_("Updated attributes: ") + ", ".join(return_message)) return redirect( mode_url( "edit_host", host=self._hostname, folder=watolib.Folder.current().path(), )) return None
def action(self) -> ActionResult: if request.var("_action") == "clear": user.need_permission("wato.auditlog") user.need_permission("wato.clear_auditlog") user.need_permission("wato.edit") return self._clear_audit_log_after_confirm() if html.request.var("_action") == "csv": user.need_permission("wato.auditlog") return self._export_audit_log(self._parse_audit_log()) return None
def _resolve_site(host): # When the site is available via URL context, use it. Otherwise it is needed # to check all sites for the requested host if request.has_var('site'): return request.var('site') with sites.prepend_site(): query = "GET hosts\nFilter: name = %s\nColumns: name" % livestatus.lqencode(host) try: return sites.live().query_value(query) except livestatus.MKLivestatusNotFoundError: raise MKUserError("host", _("The host could not be found on any active site."))
def heading_info(self): # FIXME: There is a problem with caching data and changing titles of WATO files # Everything is changed correctly but the filter object is stored in the # global multisite_filters var and self.path_to_tree is not refreshed when # rendering this title. Thus the threads might have old information about the # file titles and so on. # The call below needs to use some sort of indicator wether the cache needs # to be renewed or not. self.check_wato_data_update() current = request.var(self.ident) if current and current != "/": return self.path_to_tree.get(current)
def ajax_set_assumption() -> None: site = request.get_str_input("site") host = request.get_str_input("host") service = request.get_str_input("service") state = request.var("state") if state == "none": del user.bi_assumptions[_get_state_assumption_key(site, host, service)] elif state is not None: user.bi_assumptions[_get_state_assumption_key(site, host, service)] = int(state) else: raise Exception("ajax_set_assumption: state is None") user.save_bi_assumptions()
def _from_vars(self): self._timeperiods = watolib.timeperiods.load_timeperiods() self._name = request.var("edit") # missing -> new group # TODO: Nuke the field below? It effectively hides facts about _name for mypy. self._new = self._name is None if self._name in watolib.timeperiods.builtin_timeperiods(): raise MKUserError("edit", _("Builtin timeperiods can not be modified")) if self._new: clone_name = request.var("clone") if request.var("mode") == "import_ical": self._timeperiod = {} elif clone_name: self._name = clone_name self._timeperiod = self._get_timeperiod(self._name) else: # initialize with 24x7 config self._timeperiod = {day: [("00:00", "24:00")] for day in defines.weekday_ids()} else: self._timeperiod = self._get_timeperiod(self._name)
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 ) html.header(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 from_html_vars(self, varprefix): if request.var(self.tp_current_mode) == "1": # Fetch the timespecific settings parameters = self._get_timeperiod_valuespec().from_html_vars( varprefix) if parameters[self.tp_values_key]: return parameters # Fall back to enclosed valuespec data when no timeperiod is set return parameters[self.tp_default_value_key] # Fetch the data from the enclosed valuespec return self._enclosed_valuespec.from_html_vars(varprefix)
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 _from_vars(self) -> None: user.need_permission("wato.download_agent_output") host_name = request.var("host") if not host_name: raise MKGeneralException(_("The host is missing.")) ty = request.var("type") if ty not in ["walk", "agent"]: raise MKGeneralException(_("Invalid type specified.")) self._back_url = request.get_url_input("back_url", deflt="") or None host = watolib.Folder.current().host(host_name) if not host: raise MKGeneralException( _("Host is not managed by WATO. " 'Click <a href="%s">here</a> to go back.') % escape_attribute(self._back_url)) host.need_permission("read") self._request = FetchAgentOutputRequest(host=host, agent_type=ty)
def filter_table(self, context: VisualContext, rows: Rows) -> Rows: current = request.var(self.ident) if current not in ("no", "yes"): return rows f = current == "yes" new_rows = [] for row in rows: available = row.get("invinterface_available") if available == f: new_rows.append(row) return new_rows