def page(self) -> PageResult: """Determines the hosts to be shown""" user.need_permission("general.parent_child_topology") topology_settings = TopologySettings() if request.var("filled_in"): # Parameters from the check_mk filters self._update_topology_settings_with_context(topology_settings) elif request.var("host_name"): # Explicit host_name. Used by icon linking to Topology topology_settings.growth_root_nodes = { HostName(html.request.get_str_input_mandatory("host_name")) } else: # Default page without further context topology_settings.growth_root_nodes = self._get_default_view_hostnames( topology_settings.growth_auto_max_nodes) if request.has_var("topology_settings"): # These parameters are usually generated within javascript through user interactions try: settings_from_var = json.loads( request.get_str_input_mandatory("topology_settings")) for key, value in settings_from_var.items(): setattr(topology_settings, key, value) except (TypeError, ValueError): raise MKGeneralException( _("Invalid topology_settings %r") % topology_settings) self.show_topology(topology_settings)
def page(self) -> CBORPageResult: assert user.id is not None user.need_permission("general.manage_2fa") raw_data = request.get_data() logger.debug("Raw request: %r", raw_data) data: dict[str, object] = cbor.decode(raw_data) client_data = ClientData(data["clientDataJSON"]) att_obj = AttestationObject(data["attestationObject"]) logger.debug("Client data: %r", client_data) logger.debug("Attestation object: %r", att_obj) auth_data = make_fido2_server().register_complete( session.session_info.webauthn_action_state, client_data, att_obj ) ident = auth_data.credential_data.credential_id.hex() credentials = load_two_factor_credentials(user.id, lock=True) if ident in credentials["webauthn_credentials"]: raise MKGeneralException(_("Your WebAuthn credetial is already in use")) credentials["webauthn_credentials"][ident] = WebAuthnCredential( { "credential_id": ident, "registered_at": int(time.time()), "alias": "", "credential_data": bytes(auth_data.credential_data), } ) save_two_factor_credentials(user.id, credentials) flash(_("Registration successful")) return {"status": "OK"}
def list_rules(param): """List rules""" user.need_permission("wato.rulesets") all_sets = watolib.AllRulesets() all_sets.load() ruleset_name = param["ruleset_name"] try: ruleset = all_sets.get(ruleset_name.replace("-", ":")) except KeyError: return problem( status=400, title="Unknown ruleset.", detail=f"The ruleset of name {ruleset_name!r} is not known.", ) result = [] for folder, index, rule in ruleset.get_rules(): result.append(_serialize_rule(folder, index, rule)) return serve_json( constructors.collection_object( domain_type="rule", value=result, extensions={ "found_rules": len(result), }, ))
def show_ruleset(param): """Show a ruleset""" ruleset_name = param["ruleset_name"] user.need_permission("wato.rulesets") collection = watolib.SingleRulesetRecursively(ruleset_name) collection.load() ruleset = collection.get(ruleset_name) return serve_json(_serialize_ruleset(ruleset))
def page(self): user.need_permission("wato.backups") if request.var("job") == "restore": page: backup.PageAbstractBackupJobState = backup.PageBackupRestoreState( ) else: page = ModeBackupJobState() page.show_job_details()
def get_request(self) -> FetchAgentOutputRequest: user.need_permission("wato.download_agent_output") ascii_input = request.get_ascii_input("request") if ascii_input is None: raise MKUserError("request", _('The parameter "%s" is missing.') % "request") return FetchAgentOutputRequest.deserialize( ast.literal_eval(ascii_input))
def _check_permissions(api_call): if not user.get_attribute("automation_secret"): raise MKAuthException("The API is only available for automation users") if not config.wato_enabled: raise MKUserError(None, _("Setup is disabled on this site.")) for permission in ["wato.use", "wato.api_allowed"] + api_call.get("required_permissions", []): user.need_permission(permission)
def acknowledge_werks(werks, check_permission=True): if check_permission: user.need_permission("general.acknowledge_werks") ack_ids = load_acknowledgements() for werk in werks: ack_ids.append(werk["id"]) werk["compatible"] = "incomp_ack" save_acknowledgements(ack_ids)
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): user.need_permission("general.see_crash_reports") filename = "Checkmk_Crash_%s_%s_%s.tar.gz" % \ (urlencode(self._site_id), urlencode(self._crash_id), time.strftime("%Y-%m-%d_%H-%M-%S")) response.headers[ 'Content-Disposition'] = 'Attachment; filename=%s' % filename response.headers['Content-Type'] = 'application/x-tar' response.set_data( _pack_crash_report(self._get_serialized_crash_report()))
def _check_modify_group_permissions(group_type: GroupType) -> None: required_permissions = { "contact": ["wato.users"], "host": ["wato.groups"], "service": ["wato.groups"], } # Check permissions perms = required_permissions.get(group_type) if perms is None: raise Exception("invalid group type %r" % (group_type, )) for permission in perms: user.need_permission(permission)
def page(self): watolib.init_wato_datastructures(with_wato_lock=True) user.need_permission("wato.activate") api_request = self.webapi_request() activate_until = api_request.get("activate_until") if not activate_until: raise MKUserError("activate_until", _('Missing parameter "%s".') % "activate_until") manager = watolib.ActivateChangesManager() manager.load() affected_sites_request = ensure_str( api_request.get("sites", "").strip()) if not affected_sites_request: affected_sites = manager.dirty_and_active_activation_sites() else: affected_sites = affected_sites_request.split(",") comment: Optional[str] = api_request.get("comment", "").strip() activate_foreign = api_request.get("activate_foreign", "0") == "1" valuespec = _vs_activation("", manager.has_foreign_changes()) if valuespec: valuespec.validate_value( { "comment": comment, "foreign": activate_foreign, }, "activate", ) if comment == "": comment = None activation_id = manager.start( sites=affected_sites, activate_until=ensure_str(activate_until), comment=None if comment is None else ensure_str(comment), activate_foreign=activate_foreign, ) return { "activation_id": activation_id, }
def page(self): user.need_permission("wato.activate") api_request = self.webapi_request() # ? type of activate_until is unclear activate_until = api_request.get("activate_until") if not activate_until: raise MKUserError("activate_until", _('Missing parameter "%s".') % "activate_until") manager = watolib.ActivateChangesManager() manager.load() # ? type of api_request is unclear affected_sites_request = ensure_str( # pylint: disable= six-ensure-str-bin-call api_request.get("sites", "").strip()) if not affected_sites_request: affected_sites = manager.dirty_and_active_activation_sites() else: affected_sites = [ SiteId(s) for s in affected_sites_request.split(",") ] comment: Optional[str] = api_request.get("comment", "").strip() activate_foreign = api_request.get("activate_foreign", "0") == "1" valuespec = _vs_activation("", manager.has_foreign_changes()) if valuespec: valuespec.validate_value( { "comment": comment, "foreign": activate_foreign, }, "activate", ) if comment == "": comment = None activation_id = manager.start( sites=affected_sites, activate_until=ensure_str(activate_until), # pylint: disable= six-ensure-str-bin-call comment=comment, activate_foreign=activate_foreign, ) return { "activation_id": activation_id, }
def page(self): user.need_permission("wato.activate") api_request = self.webapi_request() activation_id = api_request.get("activation_id") if not activation_id: raise MKUserError("activation_id", _('Missing parameter "%s".') % "activation_id") manager = watolib.ActivateChangesManager() manager.load() manager.load_activation(activation_id) return manager.get_state()
def page(self): watolib.init_wato_datastructures(with_wato_lock=True) user.need_permission("wato.activate") api_request = self.webapi_request() activation_id = api_request.get("activation_id") if not activation_id: raise MKUserError("activation_id", _("Missing parameter \"%s\".") % "activation_id") manager = watolib.ActivateChangesManager() manager.load() manager.load_activation(activation_id) return manager.get_state()
def list_rulesets(param): """Search rule sets""" user.need_permission("wato.rulesets") all_sets = ( watolib.FolderRulesets(param["folder"]) if param.get("folder") else watolib.AllRulesets() ) all_sets.load() def _get_search_options(params): # We remove 'folder' because that has already been handled at the start of the endpoint. options = dict(params) if "folder" in options: del options["folder"] return options if search_options := _get_search_options(param): all_sets = watolib.SearchedRulesets(all_sets, search_options)
def action(self) -> ActionResult: if not transactions.check_transaction(): return None user.need_permission("wato.edit_hosts") changed_attributes = watolib.collect_attributes("bulk", new=False) host_names = get_hostnames_from_checkboxes() for host_name in host_names: host = watolib.Folder.current().host(host_name) host.update_attributes(changed_attributes) # call_hook_hosts_changed() is called too often. # Either offer API in class Host for bulk change or # delay saving until end somehow flash(_("Edited %d hosts") % len(host_names)) return redirect(watolib.Folder.current().url())
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 robotmk_download_page() -> cmk.gui.pages.PageResult: user.need_permission("general.see_crash_reports") site_id, host_name, service_description = _get_mandatory_request_vars() filename = "RobotMK_report_%s_%s_%s_%s.tar.gz" % ( urlencode(site_id), urlencode(host_name), urlencode(service_description), time.strftime("%Y-%m-%d_%H-%M-%S"), ) response.headers[ "Content-Disposition"] = "Attachment; filename=%s" % filename response.headers["Content-Type"] = "application/x-tar" html_content: bytes = _get_html_from_livestatus(site_id, host_name, service_description)[0] response.set_data(_pack_html_content(html_content))
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 action(self) -> ActionResult: if not transactions.check_transaction(): return None user.need_permission("wato.edit_hosts") to_clean = self._bulk_collect_cleaned_attributes() if "contactgroups" in to_clean: self._folder.need_permission("write") hosts = get_hosts_from_checkboxes() # Check all permissions before doing any edit for host in hosts: host.need_permission("write") for host in hosts: host.clean_attributes(to_clean) return redirect(self._folder.url())
def action(self) -> ActionResult: user.need_permission("wato.services") tasks = get_tasks(self._get_hosts_to_discover(), self._bulk_size) try: transactions.check_transaction() self._job.set_function( self._job.do_execute, self._mode, self._do_scan, self._error_handling, tasks ) self._job.start() except Exception as e: if config.debug: raise logger.exception("Failed to start bulk discovery") raise MKUserError( None, _("Failed to start discovery: %s") % ("%s" % e).replace("\n", "\n<br>") ) raise HTTPRedirect(self._job.detail_url())
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") num_updated, failed_hosts = watolib.check_mk_automation( self._host.site_id(), "update-dns-cache", []) infotext = _( "Successfully updated IP addresses of %d hosts.") % num_updated if failed_hosts: infotext += "<br><br><b>Hostnames failed to lookup:</b> " \ + ", ".join(["<tt>%s</tt>" % h for h in 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) watolib.Host.host(self._host.name()).edit(attributes, self._get_cluster_nodes()) self._host = folder.host(self._host.name()) if request.var("services"): 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 page(self) -> CBORPageResult: assert user.id is not None user.need_permission("general.manage_2fa") registration_data, state = make_fido2_server().register_begin( { "id": user.id.encode("utf-8"), "name": user.id, "displayName": user.alias, "icon": "", }, [ AttestedCredentialData.unpack_from(v["credential_data"])[0] for v in load_two_factor_credentials(user.id)["webauthn_credentials"].values() ], user_verification="discouraged", authenticator_attachment="cross-platform", ) session.session_info.webauthn_action_state = state logger.debug("Registration data: %r", registration_data) return registration_data
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 delete_rule(param): """Delete a rule""" user.need_permission("wato.rulesets") rule_id = param["rule_id"] rule: watolib.Rule all_sets = watolib.AllRulesets() all_sets.load() found = False for ruleset in all_sets.get_rulesets().values(): for _folder, _index, rule in ruleset.get_rules(): if rule.id == rule_id: ruleset.delete_rule(rule) all_sets.save() found = True if found: return http.Response(status=204) return problem( status=404, title="Rule not found.", detail=f"The rule with ID {rule_id!r} could not be found.", )
def rename_host(params): """Rename a host""" user.need_permission("wato.rename_hosts") if activate_changes.get_pending_changes_info(): return problem( status=409, title="Pending changes are present", detail= "Please activate all pending changes before executing a host rename process", ) host_name = params["host_name"] host: watolib.CREHost = watolib.Host.load_host(host_name) new_name = params["body"]["new_name"] _, auth_problems = perform_rename_hosts([(host.folder(), host_name, new_name)]) if auth_problems: return problem( status=422, title="Rename process failed", detail= f"It was not possible to rename the host {host_name} to {new_name}", ) return _serve_host(host, effective_attributes=False)
def move(params): """Move a host to another folder""" user.need_permission("wato.move_hosts") host_name = params["host_name"] host: watolib.CREHost = watolib.Host.load_host(host_name) _require_host_etag(host) current_folder = host.folder() target_folder: CREFolder = params["body"]["target_folder"] if target_folder is current_folder: return problem( status=400, title="Invalid move action", detail="The host is already part of the specified target folder", ) try: current_folder.move_hosts([host_name], target_folder) except MKUserError as exc: return problem( status=400, title="Problem moving host", detail=exc.message, ) return _serve_host(host, effective_attributes=False)
def do_discovery(self, discovery_result): old_autochecks: SetAutochecksTable = {} autochecks_to_save: SetAutochecksTable = {} remove_disabled_rule, add_disabled_rule, saved_services = set(), set( ), set() apply_changes = False for (table_source, check_type, _checkgroup, item, discovered_params, _check_params, descr, _state, _output, _perfdata, service_labels, found_on_nodes) in discovery_result.check_table: # Versions >2.0b2 always provide a found on nodes information # If this information is missing (fallback value is None), the remote system runs on an older version table_target = self._get_table_target(table_source, check_type, item) key = check_type, item value = descr, discovered_params, service_labels, found_on_nodes if table_source in [ DiscoveryState.MONITORED, DiscoveryState.IGNORED ]: old_autochecks[key] = value if table_source != table_target: if table_target == DiscoveryState.UNDECIDED: user.need_permission("wato.service_discovery_to_undecided") elif table_target in [ DiscoveryState.MONITORED, DiscoveryState.CLUSTERED_NEW, DiscoveryState.CLUSTERED_OLD, ]: user.need_permission("wato.service_discovery_to_undecided") elif table_target == DiscoveryState.IGNORED: user.need_permission("wato.service_discovery_to_ignored") elif table_target == DiscoveryState.REMOVED: user.need_permission("wato.service_discovery_to_removed") apply_changes = True if table_source == DiscoveryState.UNDECIDED: if table_target == DiscoveryState.MONITORED: autochecks_to_save[key] = value saved_services.add(descr) elif table_target == DiscoveryState.IGNORED: add_disabled_rule.add(descr) elif table_source == DiscoveryState.VANISHED: if table_target != DiscoveryState.REMOVED: autochecks_to_save[key] = value saved_services.add(descr) if table_target == DiscoveryState.IGNORED: add_disabled_rule.add(descr) elif table_source == DiscoveryState.MONITORED: if table_target in [ DiscoveryState.MONITORED, DiscoveryState.IGNORED, ]: autochecks_to_save[key] = value if table_target == DiscoveryState.IGNORED: add_disabled_rule.add(descr) else: saved_services.add(descr) elif table_source == DiscoveryState.IGNORED: if table_target in [ DiscoveryState.MONITORED, DiscoveryState.UNDECIDED, DiscoveryState.VANISHED, ]: remove_disabled_rule.add(descr) if table_target in [ DiscoveryState.MONITORED, DiscoveryState.IGNORED, ]: autochecks_to_save[key] = value saved_services.add(descr) if table_target == DiscoveryState.IGNORED: add_disabled_rule.add(descr) elif table_source in [ DiscoveryState.CLUSTERED_NEW, DiscoveryState.CLUSTERED_OLD, ]: autochecks_to_save[key] = value saved_services.add(descr) elif table_source in [ DiscoveryState.CLUSTERED_VANISHED, DiscoveryState.CLUSTERED_IGNORED, ]: # We keep vanished clustered services on the node with the following reason: # If a service is mapped to a cluster then there are already operations # for adding, removing, etc. of this service on the cluster. Therefore we # do not allow any operation for this clustered service on the related node. # We just display the clustered service state (OLD, NEW, VANISHED). autochecks_to_save[key] = value saved_services.add(descr) if apply_changes: need_sync = False if remove_disabled_rule or add_disabled_rule: add_disabled_rule = add_disabled_rule - remove_disabled_rule - saved_services self._save_host_service_enable_disable_rules( remove_disabled_rule, add_disabled_rule) need_sync = True self._save_services( old_autochecks, autochecks_to_save, need_sync, )
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 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))