Esempio n. 1
0
def test_edit_group_missing(web, group_type):
    group_id = "%s_testgroup_id" % group_type
    group_alias = "%s_testgroup_alias" % group_type
    group_alias2 = "%s_testgroup_otheralias" % group_type
    try:
        attributes = {"alias": group_alias}

        if cmk_version.is_managed_edition():
            attributes["customer"] = "provider"

        web.add_group(group_type, group_id, attributes)
        try:
            #web.edit_group(group_type, group_id, {"alias": group_alias2}, expect_error = True)
            web.edit_group(group_type,
                           "%s_missing" % group_id, {"alias": group_alias2},
                           expect_error=True)
        except APIError as e:
            assert str(e) != str(None)
            return

        assert False
    finally:
        web.delete_group(group_type, group_id)
Esempio n. 2
0
def test_registered_snapins():
    expected_snapins = [
        "admin",
        "admin_mini",
        "biaggr_groups",
        "biaggr_groups_tree",
        "bookmarks",
        "dashboards",
        "hostgroups",
        "master_control",
        "mkeventd_performance",
        "nagvis_maps",
        "performance",
        "search",
        "servicegroups",
        "sitestatus",
        "speedometer",
        "tactical_overview",
        "tag_tree",
        "time",
        "views",
        "wato_folders",
        "wato_foldertree",
    ]

    if not cmk_version.is_raw_edition():
        expected_snapins += [
            "cmc_stats",
            "reports",
        ]

    if cmk_version.is_managed_edition():
        expected_snapins += [
            "customers",
        ]

    assert sorted(snapin_registry.keys()) == sorted(expected_snapins)
Esempio n. 3
0
def create_password(params):
    """Create a password"""
    user.need_permission("wato.edit")
    user.need_permission("wato.passwords")
    body = params["body"]
    ident = body["ident"]
    password_details = cast(
        Password,
        {
            k: v
            for k, v in body.items() if k not in (
                "ident",
                "owned_by",
                "customer",
            )
        },
    )
    if version.is_managed_edition():
        password_details = update_customer_info(password_details,
                                                body["customer"])
    password_details[
        "owned_by"] = None if body["owned_by"] == "admin" else body["owned_by"]
    save_password(ident, password_details, new_password=True)
    return _serve_password(ident, load_password(ident))
Esempio n. 4
0
def test_edit_cg_group_with_nagvis_maps(web, site):
    dummy_map_filepath1 = "%s/etc/nagvis/maps/blabla.cfg" % site.root
    dummy_map_filepath2 = "%s/etc/nagvis/maps/bloblo.cfg" % site.root
    try:
        open(dummy_map_filepath1, "w")
        open(dummy_map_filepath2, "w")

        attributes = {"alias": "nagvis_test_alias", "nagvis_maps": ["blabla"]}

        if cmk_version.is_managed_edition():
            attributes["customer"] = "provider"

        web.add_group("contact", "nagvis_test", attributes)

        attributes["nagvis_maps"] = ["bloblo"]
        web.edit_group("contact", "nagvis_test", attributes)

        all_groups = web.get_all_groups("contact")
        assert "nagvis_test" in all_groups
        assert "bloblo" in all_groups["nagvis_test"]["nagvis_maps"]
    finally:
        web.delete_group("contact", "nagvis_test")
        os.unlink(dummy_map_filepath1)
        os.unlink(dummy_map_filepath2)
Esempio n. 5
0
    def _create_snapshots(self):
        with store.lock_checkmk_configuration():
            if not self._changes:
                raise MKUserError(
                    None, _("Currently there are no changes to activate."))

            if self._get_last_change_id() != self._activate_until:
                raise MKUserError(
                    None,
                    _("Another change has been made in the meantime. Please review it "
                      "to ensure you also want to activate it now and start the "
                      "activation again."))

            # Create (legacy) WATO config snapshot
            start = time.time()
            logger.debug("Snapshot creation started")
            # TODO: Remove/Refactor once new changes mechanism has been implemented
            #       This single function is responsible for the slow activate changes (python tar packaging..)
            snapshot_name = cmk.gui.watolib.snapshots.create_snapshot(
                self._comment)
            log_audit(None, "snapshot-created",
                      _("Created snapshot %s") % snapshot_name)

            if self._activation_id is None:
                raise Exception("activation ID is not set")
            work_dir = os.path.join(self.activation_tmp_base_dir,
                                    self._activation_id)
            if cmk_version.is_managed_edition():
                import cmk.gui.cme.managed_snapshots as managed_snapshots  # pylint: disable=no-name-in-module
                managed_snapshots.CMESnapshotManager(
                    work_dir,
                    self._get_site_configurations()).generate_snapshots()
            else:
                self._generate_snapshots(work_dir)

            logger.debug("Snapshot creation took %.4f", time.time() - start)
Esempio n. 6
0
    def _login(self, request: Mapping[str, Any]) -> None:
        site_mgmt = watolib.SiteManagementFactory().factory()
        all_sites = site_mgmt.load_sites()
        site = all_sites.get(request["site_id"])
        if not site:
            raise MKUserError(None, _("Site id not found: %s") % request["site_id"])

        response = watolib.do_site_login(site, request["username"], request["password"])

        if isinstance(response, dict):
            if cmk_version.is_managed_edition() and response["edition_short"] != "cme":
                raise MKUserError(
                    None,
                    _(
                        "The Check_MK Managed Services Edition can only "
                        "be connected with other sites using the CME."
                    ),
                )
            secret = response["login_secret"]
        else:
            secret = response

        site["secret"] = secret
        site_mgmt.save_sites(all_sites)
Esempio n. 7
0
def test_registered_permissions():
    load_dynamic_permissions()

    expected_permissions = [
        "action.acknowledge",
        "action.addcomment",
        "action.clearmodattr",
        "action.customnotification",
        "action.downtimes",
        "action.enablechecks",
        "action.fakechecks",
        "action.notifications",
        "action.remove_all_downtimes",
        "action.reschedule",
        "action.star",
        "action.delete_crash_report",
        "background_jobs.delete_foreign_jobs",
        "background_jobs.delete_jobs",
        "background_jobs.manage_jobs",
        "background_jobs.see_foreign_jobs",
        "background_jobs.stop_foreign_jobs",
        "background_jobs.stop_jobs",
        "bi.see_all",
        "dashboard.main",
        "dashboard.simple_problems",
        "dashboard.checkmk",
        "dashboard.checkmk_host",
        "general.acknowledge_werks",
        "general.act",
        "general.agent_pairing",
        "general.change_password",
        "general.manage_2fa",
        "general.configure_sidebar",
        "general.csv_export",
        "general.delete_foreign_pagetype_topic",
        "general.edit_pagetype_topic",
        "general.edit_foreign_pagetype_topic",
        "general.force_pagetype_topic",
        "general.publish_pagetype_topic",
        "general.publish_to_foreign_groups_pagetype_topic",
        "general.publish_to_groups_pagetype_topic",
        "general.see_user_pagetype_topic",
        "general.delete_foreign_bookmark_list",
        "general.delete_foreign_custom_snapin",
        "general.delete_foreign_dashboards",
        "general.delete_foreign_views",
        "general.disable_notifications",
        "general.edit_bookmark_list",
        "general.edit_custom_snapin",
        "general.edit_dashboards",
        "general.edit_foreign_bookmark_list",
        "general.edit_foreign_dashboards",
        "general.edit_foreign_views",
        "general.edit_foreign_custom_snapin",
        "general.edit_notifications",
        "general.edit_profile",
        "general.edit_user_attributes",
        "general.edit_views",
        "general.force_bookmark_list",
        "general.force_custom_snapin",
        "general.force_dashboards",
        "general.force_views",
        "general.ignore_hard_limit",
        "general.ignore_soft_limit",
        "general.logout",
        "general.message",
        "general.painter_options",
        "general.parent_child_topology",
        "general.publish_bookmark_list",
        "general.publish_to_foreign_groups_bookmark_list",
        "general.publish_to_groups_bookmark_list",
        "general.publish_custom_snapin",
        "general.publish_to_foreign_groups_custom_snapin",
        "general.publish_to_groups_custom_snapin",
        "general.publish_dashboards",
        "general.publish_dashboards_to_foreign_groups",
        "general.publish_dashboards_to_groups",
        "general.publish_views",
        "general.publish_views_to_foreign_groups",
        "general.publish_views_to_groups",
        "general.see_all",
        "general.see_availability",
        "general.see_crash_reports",
        "general.see_failed_notifications",
        "general.see_failed_notifications_24h",
        "general.see_sidebar",
        "general.see_stales_in_tactical_overview",
        "general.see_user_bookmark_list",
        "general.see_user_custom_snapin",
        "general.see_user_dashboards",
        "general.see_user_views",
        "general.server_side_requests",
        "general.use",
        "general.view_option_columns",
        "general.view_option_refresh",
        "icons_and_actions.action_menu",
        "icons_and_actions.aggregation_checks",
        "icons_and_actions.aggregations",
        "icons_and_actions.check_manpage",
        "icons_and_actions.check_period",
        "icons_and_actions.crashed_check",
        "icons_and_actions.custom_action",
        "icons_and_actions.download_agent_output",
        "icons_and_actions.download_snmp_walk",
        "icons_and_actions.icon_image",
        "icons_and_actions.inventory",
        "icons_and_actions.logwatch",
        "icons_and_actions.mkeventd",
        "icons_and_actions.notes",
        "icons_and_actions.perfgraph",
        "icons_and_actions.prediction",
        "icons_and_actions.reschedule",
        "icons_and_actions.rule_editor",
        "icons_and_actions.stars",
        "icons_and_actions.status_acknowledged",
        "icons_and_actions.status_active_checks",
        "icons_and_actions.status_comments",
        "icons_and_actions.status_downtimes",
        "icons_and_actions.status_flapping",
        "icons_and_actions.status_notification_period",
        "icons_and_actions.status_notifications_enabled",
        "icons_and_actions.status_passive_checks",
        "icons_and_actions.status_service_period",
        "icons_and_actions.status_stale",
        "icons_and_actions.wato",
        "icons_and_actions.parent_child_topology",
        "mkeventd.actions",
        "mkeventd.activate",
        "mkeventd.archive_events_of_hosts",
        "mkeventd.changestate",
        "mkeventd.config",
        "mkeventd.delete",
        "mkeventd.edit",
        "mkeventd.see_in_tactical_overview",
        "mkeventd.seeall",
        "mkeventd.seeunrelated",
        "mkeventd.switchmode",
        "mkeventd.update",
        "mkeventd.update_comment",
        "mkeventd.update_contact",
        "nagvis.*_*_*",
        "nagvis.Map_delete",
        "nagvis.Map_delete_*",
        "nagvis.Map_edit",
        "nagvis.Map_edit_*",
        "nagvis.Map_view",
        "nagvis.Map_view_*",
        "nagvis.Rotation_view_*",
        "notification_plugin.asciimail",
        "notification_plugin.cisco_webex_teams",
        "notification_plugin.jira_issues",
        "notification_plugin.mail",
        "notification_plugin.mkeventd",
        "notification_plugin.opsgenie_issues",
        "notification_plugin.pagerduty",
        "notification_plugin.pushover",
        "notification_plugin.servicenow",
        "notification_plugin.signl4",
        "notification_plugin.ilert",
        "notification_plugin.slack",
        "notification_plugin.sms",
        "notification_plugin.sms_api",
        "notification_plugin.spectrum",
        "notification_plugin.victorops",
        "sidesnap.admin_mini",
        "sidesnap.biaggr_groups",
        "sidesnap.biaggr_groups_tree",
        "sidesnap.bookmarks",
        "sidesnap.dashboards",
        "sidesnap.hostgroups",
        "sidesnap.master_control",
        "sidesnap.mkeventd_performance",
        "sidesnap.nagvis_maps",
        "sidesnap.performance",
        "sidesnap.search",
        "sidesnap.servicegroups",
        "sidesnap.sitestatus",
        "sidesnap.speedometer",
        "sidesnap.tactical_overview",
        "sidesnap.tag_tree",
        "sidesnap.time",
        "sidesnap.views",
        "sidesnap.wato_foldertree",
        "view.aggr_all",
        "view.aggr_all_api",
        "view.aggr_group",
        "view.aggr_host",
        "view.aggr_hostgroup_boxed",
        "view.aggr_hostnameaggrs",
        "view.aggr_hostproblems",
        "view.aggr_problems",
        "view.aggr_service",
        "view.aggr_single",
        "view.aggr_single_api",
        "view.aggr_singlehost",
        "view.aggr_singlehosts",
        "view.aggr_summary",
        "view.alerthandlers",
        "view.alertstats",
        "view.allhosts",
        "view.allservices",
        "view.bi_map_hover_host",
        "view.bi_map_hover_service",
        "view.api_downtimes",
        "view.comments",
        "view.comments_of_host",
        "view.comments_of_service",
        "view.contactnotifications",
        "view.crash_reports",
        "view.downtime_history",
        "view.downtimes",
        "view.downtimes_of_host",
        "view.downtimes_of_service",
        "view.docker_containers",
        "view.docker_nodes",
        "view.vpshere_vms",
        "view.vsphere_servers",
        "view.ec_event",
        "view.ec_event_mobile",
        "view.ec_events",
        "view.ec_events_mobile",
        "view.ec_events_of_host",
        "view.ec_events_of_monhost",
        "view.ec_history_of_event",
        "view.ec_history_of_host",
        "view.ec_history_recent",
        "view.ec_historyentry",
        "view.events",
        "view.events_dash",
        "view.failed_notifications",
        "view.host",
        "view.host_crit",
        "view.host_dt_hist",
        "view.host_export",
        "view.host_ok",
        "view.host_pending",
        "view.host_unknown",
        "view.host_warn",
        "view.hostevents",
        "view.hostgroup",
        "view.hostgroup_up",
        "view.hostgroup_down",
        "view.hostgroup_unreach",
        "view.hostgroup_pend",
        "view.hostgroups",
        "view.hostgroupservices",
        "view.hostgroupservices_ok",
        "view.hostgroupservices_warn",
        "view.hostgroupservices_crit",
        "view.hostgroupservices_unknwn",
        "view.hostgroupservices_pend",
        "view.hostnotifications",
        "view.hostpnp",
        "view.hostproblems",
        "view.hostproblems_dash",
        "view.hosts",
        "view.hoststatus",
        "view.hostsvcevents",
        "view.hostsvcnotifications",
        "view.inv_host",
        "view.inv_host_history",
        "view.inv_hosts_cpu",
        "view.inv_hosts_ports",
        "view.invbackplane_of_host",
        "view.invbackplane_search",
        "view.invchassis_of_host",
        "view.invchassis_search",
        "view.invcmksites_of_host",
        "view.invcmksites_search",
        "view.invcmkversions_of_host",
        "view.invcmkversions_search",
        "view.invcontainer_of_host",
        "view.invcontainer_search",
        "view.invdockercontainers_of_host",
        "view.invdockercontainers_search",
        "view.invdockerimages_of_host",
        "view.invdockerimages_search",
        "view.invfan_of_host",
        "view.invfan_search",
        "view.invibmmqchannels_of_host",
        "view.invibmmqchannels_search",
        "view.invibmmqmanagers_of_host",
        "view.invibmmqmanagers_search",
        "view.invibmmqqueues_of_host",
        "view.invibmmqqueues_search",
        "view.invinterface_of_host",
        "view.invinterface_search",
        "view.invkernelconfig_of_host",
        "view.invkernelconfig_search",
        "view.invmodule_of_host",
        "view.invmodule_search",
        "view.invoradataguardstats_of_host",
        "view.invoradataguardstats_search",
        "view.invorainstance_of_host",
        "view.invorainstance_search",
        "view.invorarecoveryarea_of_host",
        "view.invorarecoveryarea_search",
        "view.invorasga_of_host",
        "view.invorasga_search",
        "view.invorapga_of_host",
        "view.invorapga_search",
        "view.invoratablespace_of_host",
        "view.invoratablespace_search",
        "view.invorasystemparameter_of_host",
        "view.invorasystemparameter_search",
        "view.invother_of_host",
        "view.invother_search",
        "view.invpsu_of_host",
        "view.invpsu_search",
        "view.invsensor_of_host",
        "view.invsensor_search",
        "view.invstack_of_host",
        "view.invstack_search",
        "view.invswpac_of_host",
        "view.invswpac_search",
        "view.invtunnels_of_host",
        "view.invtunnels_search",
        "view.invunknown_of_host",
        "view.invunknown_search",
        "view.logfile",
        "view.mobile_contactnotifications",
        "view.mobile_events",
        "view.mobile_host",
        "view.mobile_hostproblems",
        "view.mobile_hostproblems_unack",
        "view.mobile_hoststatus",
        "view.mobile_hostsvcevents",
        "view.mobile_hostsvcnotifications",
        "view.mobile_notifications",
        "view.mobile_searchhost",
        "view.mobile_searchsvc",
        "view.mobile_service",
        "view.mobile_svcevents",
        "view.mobile_svcnotifications",
        "view.mobile_svcproblems",
        "view.mobile_svcproblems_unack",
        "view.nagstamon_hosts",
        "view.nagstamon_svc",
        "view.notifications",
        "view.pending_discovery",
        "view.pendingsvc",
        "view.perf_matrix",
        "view.perf_matrix_search",
        "view.problemsofhost",
        "view.recentsvc",
        "view.searchhost",
        "view.searchpnp",
        "view.searchsvc",
        "view.service",
        "view.service_check_durations",
        "view.servicedesc",
        "view.servicedescpnp",
        "view.servicegroup",
        "view.sitehosts",
        "view.sitesvcs",
        "view.sitesvcs_crit",
        "view.sitesvcs_ok",
        "view.sitesvcs_pend",
        "view.sitesvcs_unknwn",
        "view.sitesvcs_warn",
        "view.stale_hosts",
        "view.svc_dt_hist",
        "view.svcevents",
        "view.svcgroups",
        "view.svcnotifications",
        "view.svcproblems",
        "view.svcproblems_dash",
        "view.topology_hover_host",
        "view.topology_filters",
        "view.uncheckedsvc",
        "view.unmonitored_services",
        "wato.activate",
        "wato.activateforeign",
        "wato.add_or_modify_executables",
        "wato.all_folders",
        "wato.analyze_config",
        "wato.api_allowed",
        "wato.auditlog",
        "wato.automation",
        "wato.backups",
        "wato.bi_admin",
        "wato.bi_rules",
        "wato.check_plugins",
        "wato.clear_auditlog",
        "wato.clone_hosts",
        "wato.custom_attributes",
        "wato.diag_host",
        "wato.diagnostics",
        "wato.download_agent_output",
        "wato.download_agents",
        "wato.edit",
        "wato.edit_all_passwords",
        "wato.edit_all_predefined_conditions",
        "wato.edit_folders",
        "wato.edit_hosts",
        "wato.global",
        "wato.groups",
        "wato.hosts",
        "wato.hosttags",
        "wato.icons",
        "wato.manage_folders",
        "wato.manage_hosts",
        "wato.move_hosts",
        "wato.notifications",
        "wato.parentscan",
        "wato.passwords",
        "wato.pattern_editor",
        "wato.random_hosts",
        "wato.rename_hosts",
        "wato.rulesets",
        "wato.see_all_folders",
        "wato.seeall",
        "wato.service_discovery_to_ignored",
        "wato.service_discovery_to_monitored",
        "wato.service_discovery_to_removed",
        "wato.service_discovery_to_undecided",
        "wato.services",
        "wato.set_read_only",
        "wato.sites",
        "wato.snapshots",
        "wato.timeperiods",
        "wato.update_dns_cache",
        "wato.use",
        "wato.users",
        "wato.show_last_user_activity",
        "view.cmk_servers",
        "view.cmk_sites",
        "view.cmk_sites_of_host",
        "view.host_graphs",
        "view.service_graphs",
    ]

    if not cmk_version.is_raw_edition():
        expected_permissions += [
            "agent_registration.edit",
            "dashboard.linux_hosts_overview",
            "dashboard.linux_single_overview",
            "dashboard.windows_hosts_overview",
            "dashboard.windows_single_overview",
            "dashboard.problems",
            "dashboard.site",
            "dashboard.ntop_alerts",
            "dashboard.ntop_flows",
            "dashboard.ntop_top_talkers",
            "general.edit_reports",
            "icons_and_actions.agent_deployment",
            "icons_and_actions.status_shadow",
            "report.bi_availability",
            "report.default",
            "report.host",
            "report.instant",
            "report.instant_availability",
            "report.instant_graph_collection",
            "report.instant_view",
            "report.service_availability",
            "report.host_performance_graphs",
            "sidesnap.cmc_stats",
            "sidesnap.reports",
            "view.allhosts_deploy",
            "view.ntop_interfaces",
            "wato.agent_deploy_custom_files",
            "wato.agent_deployment",
            "wato.agents",
            "wato.alert_handlers",
            "wato.bake_agents",
            "wato.dcd_connections",
            "wato.download_all_agents",
            "wato.license_usage",
            "wato.influxdb_connections",
            "wato.submit_license_usage",
            "wato.manage_mkps",
            "wato.mkps",
            "wato.sign_agents",
            "general.delete_foreign_custom_graph",
            "general.delete_foreign_forecast_graph",
            "general.delete_foreign_graph_collection",
            "general.delete_foreign_graph_tuning",
            "general.delete_foreign_reports",
            "general.delete_foreign_sla_configuration",
            "general.delete_foreign_stored_report",
            "general.delete_stored_report",
            "general.edit_custom_graph",
            "general.edit_forecast_graph",
            "general.edit_foreign_forecast_graph",
            "general.edit_foreign_custom_graph",
            "general.edit_foreign_graph_collection",
            "general.edit_foreign_graph_tuning",
            "general.edit_foreign_reports",
            "general.edit_foreign_sla_configuration",
            "general.edit_graph_collection",
            "general.edit_graph_tuning",
            "general.edit_sla_configuration",
            "general.force_custom_graph",
            "general.publish_forecast_graph",
            "general.force_graph_collection",
            "general.force_graph_tuning",
            "general.publish_graph_collection",
            "general.publish_to_foreign_groups_graph_collection",
            "general.publish_to_groups_graph_collection",
            "general.publish_graph_tuning",
            "general.publish_to_foreign_groups_graph_tuning",
            "general.publish_to_groups_graph_tuning",
            "general.publish_reports",
            "general.publish_reports_to_foreign_groups",
            "general.publish_reports_to_groups",
            "general.publish_sla_configuration",
            "general.publish_to_foreign_groups_sla_configuration",
            "general.publish_to_groups_sla_configuration",
            "general.publish_stored_report",
            "general.publish_to_foreign_groups_forecast_graph",
            "general.publish_to_groups_forecast_graph",
            "general.see_user_custom_graph",
            "general.see_user_forecast_graph",
            "general.see_user_graph_collection",
            "general.see_user_graph_tuning",
            "general.see_user_reports",
            "general.see_user_sla_configuration",
            "general.see_user_stored_report",
            "general.reporting",
            "general.schedule_reports",
            "general.schedule_reports_all",
            "general.force_forecast_graph",
            "general.force_reports",
            "general.force_sla_configuration",
            "general.instant_reports",
            "general.publish_custom_graph",
            "general.publish_to_foreign_groups_custom_graph",
            "general.publish_to_groups_custom_graph",
            "icons_and_actions.deployment_status",
            "icons_and_actions.ntop_host",
        ]

    if cmk_version.is_managed_edition():
        expected_permissions += [
            "wato.customer_management",
            "view.customers",
            "view.customer_hosts",
            "view.customer_hosts_up",
            "view.customer_hosts_down",
            "view.customer_hosts_pend",
            "view.customer_hosts_unreach",
            "sidesnap.customers",
        ]

    assert sorted(expected_permissions) == sorted(permission_registry.keys())

    for perm in permission_registry.values():
        assert isinstance(perm.description, (str, LazyString))
        assert isinstance(perm.title, (str, LazyString))
        assert isinstance(perm.defaults, list)
# -*- coding: utf-8 -*-
# Copyright (C) 2020 tribe29 GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

import json
import random
import string

import pytest

from tests.unit.cmk.gui.conftest import WebTestAppForCMK

from cmk.utils import version

managedtest = pytest.mark.skipif(not version.is_managed_edition(),
                                 reason="see #7213")


@managedtest
@pytest.mark.parametrize("group_type", ["host", "contact", "service"])
def test_openapi_groups(group_type, aut_user_auth_wsgi_app: WebTestAppForCMK):

    name = _random_string(10)
    alias = _random_string(10)

    group = {"name": name, "alias": alias, "customer": "provider"}

    base = "/NO_SITE/check_mk/api/1.0"
    resp = aut_user_auth_wsgi_app.call_method(
        "post",
Esempio n. 9
0
    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"):
            EmailAddress().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_version.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
            uid = None if self._user_id is None else UserId(self._user_id)
            if (self._is_new_user
                    or (config.user_may(uid, 'general.edit_profile')
                        and config.user_may(uid, '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"))
        is_member_of_at_least_one = False
        for role_id, role in sorted(self._roles.items(),
                                    key=lambda x: (x[1]["alias"], x[0])):
            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"))
            user_np = self._user.get("notification_period")
            if not isinstance(user_np, str):
                raise Exception("invalid notification period %r" % (user_np, ))
            html.dropdown("notification_period",
                          [(id_, "%s" % (tp["alias"]))
                           for (id_, tp) in self._timeperiods.items()],
                          deflt=user_np,
                          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()
Esempio n. 10
0
def group_edit_details(body):
    group_details = {k: v for k, v in body.items() if k != "customer"}

    if version.is_managed_edition() and "customer" in body:
        group_details = update_customer_info(group_details, body["customer"])
    return group_details
Esempio n. 11
0
def event_rule_matches_non_inverted(rule_pack, rule, event):
    if not match_ipv4_network(rule.get("match_ipaddress", "0.0.0.0/0"),
                              event["ipaddress"]):
        return _("The source IP address does not match.")

    if match(rule.get("match_host"), event["host"], complete=True) is False:
        return _("The host name does not match.")

    if match(rule.get("match_application"),
             event["application"],
             complete=False) is False:
        return _("The application (syslog tag) does not match")

    if "match_facility" in rule and event["facility"] != rule["match_facility"]:
        return _("The syslog facility does not match")

    # First try cancelling rules
    if "match_ok" in rule or "cancel_priority" in rule:
        if "cancel_priority" in rule:
            up, lo = rule["cancel_priority"]
            cp = event["priority"] >= lo and event["priority"] <= up
        else:
            cp = True

        match_groups = match(rule.get("match_ok", ""),
                             event["text"],
                             complete=False)
        if match_groups is not False and cp:
            if match_groups is True:
                match_groups = ()
            return True, match_groups

    try:
        match_groups = match(rule.get("match"), event["text"], complete=False)
    except Exception as e:
        return _("Invalid regular expression: %s") % e
    if match_groups is False:
        return _("The message text does not match the required pattern.")

    if "match_priority" in rule:
        prio_from, prio_to = rule["match_priority"]
        if prio_from > prio_to:
            prio_to, prio_from = prio_from, prio_to
        p = event["priority"]
        if p < prio_from or p > prio_to:
            return _("The syslog priority is not in the required range.")

    if "match_sl" in rule:
        sl_from, sl_to = rule["match_sl"]
        if sl_from > sl_to:
            sl_to, sl_from = sl_from, sl_to
        p = event.get("sl")
        if p is None:
            return _("No service level is set in event")

        if p < sl_from or p > sl_to:
            return _("Wrong service level %d (need %d..%d)") % (p, sl_from,
                                                                sl_to)

    if "match_timeperiod" in rule:
        reason = check_timeperiod(rule["match_timeperiod"])
        if reason:
            return reason

    if cmk_version.is_managed_edition():
        import cmk.gui.cme.managed as managed  # pylint: disable=no-name-in-module
        if "customer" in rule_pack:
            rule_customer_id = rule_pack["customer"]
        else:
            rule_customer_id = rule.get("customer", managed.SCOPE_GLOBAL)

        site_customer_id = managed.get_customer_id(config.sites[event["site"]])

        if rule_customer_id != managed.SCOPE_GLOBAL and site_customer_id != rule_customer_id:
            return _("Wrong customer")

    if match_groups is True:
        match_groups = ()  # no matching groups
    return False, match_groups
Esempio n. 12
0
def test_generate_pre_17_site_snapshot(edition_short, monkeypatch, tmp_path,
                                       with_user_login, remote_site):
    snapshot_data_collector_class = ("CMESnapshotDataCollector"
                                     if edition_short == "cme" else
                                     "CRESnapshotDataCollector")

    is_pre_17_site = True
    monkeypatch.setattr(cmk_version, "edition_short", lambda: edition_short)
    monkeypatch.setattr(utils, "is_pre_17_remote_site",
                        lambda s: is_pre_17_site)

    activation_manager = _get_activation_manager(monkeypatch, remote_site)
    snapshot_settings = _create_sync_snapshot(
        activation_manager,
        snapshot_data_collector_class,
        monkeypatch,
        tmp_path,
        is_pre_17_site,
        remote_site,
    )

    # And now check the resulting snapshot contents
    unpack_dir = tmp_path / "snapshot_unpack"
    if unpack_dir.exists():
        shutil.rmtree(str(unpack_dir))

    with tarfile.open(snapshot_settings.snapshot_path, "r") as t:
        t.extractall(str(unpack_dir))

    expected_subtars = [
        "auth.secret.tar",
        "auth.serials.tar",
        "check_mk.tar",
        "diskspace.tar",
        "htpasswd.tar",
        "mkeventd_mkp.tar",
        "mkeventd.tar",
        "multisite.tar",
        "sitespecific.tar",
        "usersettings.tar",
    ]

    if is_enterprise_repo():
        expected_subtars += [
            "dcd.tar",
            "mknotify.tar",
        ]

    if config.sites[remote_site].get("replicate_mkps", False):
        expected_subtars += [
            "local.tar",
            "mkps.tar",
        ]

    if not cmk_version.is_raw_edition():
        expected_subtars.append("liveproxyd.tar")

    if cmk_version.is_managed_edition():
        expected_subtars += [
            "customer_check_mk.tar",
            "customer_gui_design.tar",
            "customer_multisite.tar",
            "gui_logo.tar",
            "gui_logo_dark.tar",
            "gui_logo_facelift.tar",
        ]

    assert sorted(f.name
                  for f in unpack_dir.iterdir()) == sorted(expected_subtars)

    expected_files: Dict[str, List[str]] = {
        "mkeventd_mkp.tar": [],
        "multisite.tar": ["global.mk", "users.mk"],
        "usersettings.tar": [with_user_login],
        "mkeventd.tar": [],
        "check_mk.tar": ["hosts.mk", "contacts.mk"],
        "htpasswd.tar": ["htpasswd"],
        "liveproxyd.tar": [],
        "sitespecific.tar": ["sitespecific.mk"],
        "auth.secret.tar": [],
        "dcd.tar": [],
        "auth.serials.tar": ["auth.serials"],
        "mknotify.tar": [],
        "diskspace.tar": [],
    }

    if config.sites[remote_site].get("replicate_mkps", False):
        expected_files.update({"local.tar": [], "mkps.tar": []})

    if cmk_version.is_managed_edition():
        expected_files.update({
            "customer_check_mk.tar": ["customer.mk"],
            "customer_gui_design.tar": [],
            "customer_multisite.tar": ["customer.mk"],
            "gui_logo.tar": [],
            "gui_logo_dark.tar": [],
            "gui_logo_facelift.tar": [],
            # TODO: Shouldn't we clean up these subtle differences?
            "mkeventd.tar": ["rules.mk"],
            "check_mk.tar": ["groups.mk", "contacts.mk"],
            "multisite.tar": [
                "bi.mk",
                "customers.mk",
                "global.mk",
                "groups.mk",
                "user_connections.mk",
                "users.mk",
            ],
        })

    if not cmk_version.is_raw_edition():
        expected_files["liveproxyd.tar"] = []

    # And now check the subtar contents
    for subtar in unpack_dir.iterdir():
        subtar_unpack_dir = unpack_dir / subtar.stem
        subtar_unpack_dir.mkdir(parents=True, exist_ok=True)

        with tarfile.open(str(subtar), "r") as s:
            s.extractall(str(subtar_unpack_dir))

        files = sorted(
            str(f.relative_to(subtar_unpack_dir))
            for f in subtar_unpack_dir.iterdir())

        assert sorted(expected_files[subtar.name]) == files, (
            "Subtar %s has wrong files" % subtar.name)
Esempio n. 13
0
def get_host_attributes(hostname: HostName,
                        config_cache: ConfigCache) -> ObjectAttributes:
    host_config = config_cache.get_host_config(hostname)
    attrs = host_config.extra_host_attributes

    # Pre 1.6 legacy attribute. We have changed our whole code to use the
    # livestatus column "tags" which is populated by all attributes starting with
    # "__TAG_" instead. We may deprecate this is one day.
    attrs["_TAGS"] = " ".join(
        sorted(config_cache.get_host_config(hostname).tags))

    attrs.update(_get_tag_attributes(host_config.tag_groups, "TAG"))
    attrs.update(_get_tag_attributes(host_config.labels, "LABEL"))
    attrs.update(_get_tag_attributes(host_config.label_sources, "LABELSOURCE"))

    if "alias" not in attrs:
        attrs["alias"] = host_config.alias

    # Now lookup configured IP addresses
    v4address: Optional[str] = None
    if host_config.is_ipv4_host:
        v4address = ip_address_of(host_config, 4)

    if v4address is None:
        v4address = ""
    attrs["_ADDRESS_4"] = v4address

    v6address: Optional[str] = None
    if host_config.is_ipv6_host:
        v6address = ip_address_of(host_config, 6)
    if v6address is None:
        v6address = ""
    attrs["_ADDRESS_6"] = v6address

    ipv6_primary = host_config.is_ipv6_primary
    if ipv6_primary:
        attrs["address"] = attrs["_ADDRESS_6"]
        attrs["_ADDRESS_FAMILY"] = "6"
    else:
        attrs["address"] = attrs["_ADDRESS_4"]
        attrs["_ADDRESS_FAMILY"] = "4"

    add_ipv4addrs, add_ipv6addrs = host_config.additional_ipaddresses
    if add_ipv4addrs:
        attrs["_ADDRESSES_4"] = " ".join(add_ipv4addrs)
        for nr, ipv4_address in enumerate(add_ipv4addrs):
            key = "_ADDRESS_4_%s" % (nr + 1)
            attrs[key] = ipv4_address

    if add_ipv6addrs:
        attrs["_ADDRESSES_6"] = " ".join(add_ipv6addrs)
        for nr, ipv6_address in enumerate(add_ipv6addrs):
            key = "_ADDRESS_6_%s" % (nr + 1)
            attrs[key] = ipv6_address

    # Add the optional WATO folder path
    path = config.host_paths.get(hostname)
    if path:
        attrs["_FILENAME"] = path

    # Add custom user icons and actions
    actions = host_config.icons_and_actions
    if actions:
        attrs["_ACTIONS"] = ",".join(actions)

    if cmk_version.is_managed_edition():
        attrs[
            "_CUSTOMER"] = config.current_customer  # type: ignore[attr-defined]

    return attrs
Esempio n. 14
0
def has_custom_logo() -> bool:
    return cmk_version.is_managed_edition() and customers.get(
        current_customer, {}).get("globals", {}).get("logo")
Esempio n. 15
0
def _expected_replication_paths():
    expected = [
        ReplicationPath('dir', 'check_mk', 'etc/check_mk/conf.d/wato/', []),
        ReplicationPath('dir', 'multisite', 'etc/check_mk/multisite.d/wato/', []),
        ReplicationPath('file', 'htpasswd', 'etc/htpasswd', []),
        ReplicationPath('file', 'auth.secret', 'etc/auth.secret', []),
        ReplicationPath('file', 'auth.serials', 'etc/auth.serials', []),
        ReplicationPath('dir', 'usersettings', 'var/check_mk/web', ['*/report-thumbnails']),
        ReplicationPath('dir', 'mkps', 'var/check_mk/packages', []),
        ReplicationPath('dir', 'local', 'local', []),
    ]

    if not cmk_version.is_raw_edition():
        expected += [
            ReplicationPath('dir', 'liveproxyd', 'etc/check_mk/liveproxyd.d/wato/', []),
        ]

    if testlib.is_enterprise_repo():
        expected += [
            ReplicationPath('dir', 'dcd', 'etc/check_mk/dcd.d/wato/', []),
            ReplicationPath('dir', 'mknotify', 'etc/check_mk/mknotifyd.d/wato', []),
        ]

    expected += [
        ReplicationPath('dir', 'mkeventd', 'etc/check_mk/mkeventd.d/wato', []),
        ReplicationPath('dir', 'mkeventd_mkp', 'etc/check_mk/mkeventd.d/mkp/rule_packs', []),
        ReplicationPath('file', 'diskspace', 'etc/diskspace.conf', []),
    ]

    if cmk_version.is_managed_edition():
        expected += [
            ReplicationPath(ty='file',
                            ident='customer_check_mk',
                            site_path='etc/check_mk/conf.d/customer.mk',
                            excludes=[]),
            ReplicationPath(ty='file',
                            ident='customer_gui_design',
                            site_path='etc/check_mk/multisite.d/zzz_customer_gui_design.mk',
                            excludes=[]),
            ReplicationPath(ty='file',
                            ident='customer_multisite',
                            site_path='etc/check_mk/multisite.d/customer.mk',
                            excludes=[]),
            ReplicationPath(
                ty='file',
                ident='gui_logo',
                site_path='local/share/check_mk/web/htdocs/themes/classic/images/sidebar_top.png',
                excludes=[]),
            ReplicationPath(
                ty='file',
                ident='gui_logo_dark',
                site_path='local/share/check_mk/web/htdocs/themes/modern-dark/images/mk-logo.png',
                excludes=[]),
            ReplicationPath(
                ty='file',
                ident='gui_logo_facelift',
                site_path='local/share/check_mk/web/htdocs/themes/facelift/images/mk-logo.png',
                excludes=[]),
        ]

    return expected
Esempio n. 16
0
def expected_items() -> Dict[str, List[str]]:
    agents_items = []

    if cmk_version.is_raw_edition():
        agents_items += [
            "download_agents_linux",
            "download_agents_windows",
        ]
    else:
        agents_items += [
            "agents",
        ]

    agents_items += [
        "download_agents",
    ]

    if not cmk_version.is_raw_edition():
        agents_items.append("agent_registration")

    agents_items += [
        "wato.py?group=vm_cloud_container&mode=rulesets",
        "wato.py?group=datasource_programs&mode=rulesets",
        "wato.py?group=agent&mode=rulesets",
        "wato.py?group=snmp&mode=rulesets",
    ]

    events_items = [
        "notifications",
        "mkeventd_rule_packs",
    ]

    if not cmk_version.is_raw_edition():
        events_items.append("alert_handlers")

    maintenance_items = ["backup"]

    if not cmk_version.is_raw_edition():
        maintenance_items.append("license_usage")
        maintenance_items.append("mkps")

    maintenance_items += [
        "diagnostics",
        "analyze_config",
        "background_jobs_overview",
    ]

    hosts_items = [
        "folder",
        "wato.py?group=host_monconf&mode=rulesets",
        "tags",
    ]

    if not cmk_version.is_raw_edition():
        hosts_items.append("dcd_connections")

    hosts_items += [
        "host_groups",
        "host_attrs",
        "wato.py?group=inventory&mode=rulesets",
    ]

    users_items = [
        "users",
        "contact_groups",
        "roles",
        "ldap_config",
        "user_attrs",
    ]

    if cmk_version.is_managed_edition():
        users_items.insert(0, "customer_management")

    expected_items_dict = {
        "agents":
        agents_items,
        "events":
        events_items,
        "general": [
            "rule_search",
            "globalvars",
            "read_only",
            "predefined_conditions",
            "timeperiods",
            "passwords",
            "sites",
            "auditlog",
            "icons",
        ],
        "hosts":
        hosts_items,
        "maintenance":
        maintenance_items,
        "services": [
            "wato.py?group=monconf&mode=rulesets",
            "wato.py?group=checkparams&mode=rulesets",
            "wato.py?group=static&mode=rulesets",
            "wato.py?group=activechecks&mode=rulesets",
            "wato.py?group=custom_checks&mode=rulesets",
            "service_groups",
            "check_plugins",
        ],
        "bi": ["bi_packs"],
        "users":
        users_items,
    }

    if not cmk_version.is_raw_edition():
        expected_items_dict.update({"custom": ["influxdb_connections"]})

    return expected_items_dict
Esempio n. 17
0
def test_registered_permissions():
    expected_permissions = [
        'action.acknowledge',
        'action.addcomment',
        'action.clearmodattr',
        'action.customnotification',
        'action.downtimes',
        'action.enablechecks',
        'action.fakechecks',
        'action.notifications',
        'action.remove_all_downtimes',
        'action.reschedule',
        'action.star',
        'action.delete_crash_report',
        'background_jobs.delete_foreign_jobs',
        'background_jobs.delete_jobs',
        'background_jobs.manage_jobs',
        'background_jobs.see_foreign_jobs',
        'background_jobs.stop_foreign_jobs',
        'background_jobs.stop_jobs',
        'bi.see_all',
        'dashboard.main',
        'dashboard.simple_problems',
        'dashboard.topology',
        'general.acknowledge_werks',
        'general.act',
        'general.change_password',
        'general.configure_sidebar',
        'general.csv_export',
        'general.delete_foreign_bookmark_list',
        'general.delete_foreign_custom_snapin',
        'general.delete_foreign_dashboards',
        'general.delete_foreign_views',
        'general.disable_notifications',
        'general.edit_bookmark_list',
        'general.edit_custom_snapin',
        'general.edit_dashboards',
        'general.edit_foreign_bookmark_list',
        'general.edit_foreign_dashboards',
        'general.edit_foreign_views',
        'general.edit_foreign_custom_snapin',
        'general.edit_notifications',
        'general.edit_profile',
        'general.edit_user_attributes',
        'general.edit_views',
        'general.force_bookmark_list',
        'general.force_custom_snapin',
        'general.force_dashboards',
        'general.force_views',
        'general.ignore_hard_limit',
        'general.ignore_soft_limit',
        'general.logout',
        'general.notify',
        'general.painter_options',
        'general.publish_bookmark_list',
        'general.publish_to_foreign_groups_bookmark_list',
        'general.publish_custom_snapin',
        'general.publish_to_foreign_groups_custom_snapin',
        'general.publish_dashboards',
        'general.publish_dashboards_to_foreign_groups',
        'general.publish_views',
        'general.publish_views_to_foreign_groups',
        'general.see_all',
        'general.see_availability',
        'general.see_crash_reports',
        'general.see_failed_notifications',
        'general.see_failed_notifications_24h',
        'general.see_sidebar',
        'general.see_stales_in_tactical_overview',
        'general.see_user_bookmark_list',
        'general.see_user_custom_snapin',
        'general.see_user_dashboards',
        'general.see_user_views',
        'general.use',
        'general.view_option_columns',
        'general.view_option_refresh',
        'icons_and_actions.action_menu',
        'icons_and_actions.aggregation_checks',
        'icons_and_actions.aggregations',
        'icons_and_actions.check_manpage',
        'icons_and_actions.check_period',
        'icons_and_actions.crashed_check',
        'icons_and_actions.custom_action',
        'icons_and_actions.download_agent_output',
        'icons_and_actions.download_snmp_walk',
        'icons_and_actions.icon_image',
        'icons_and_actions.inventory',
        'icons_and_actions.logwatch',
        'icons_and_actions.mkeventd',
        'icons_and_actions.notes',
        'icons_and_actions.perfgraph',
        'icons_and_actions.prediction',
        'icons_and_actions.reschedule',
        'icons_and_actions.rule_editor',
        'icons_and_actions.stars',
        'icons_and_actions.status_acknowledged',
        'icons_and_actions.status_active_checks',
        'icons_and_actions.status_comments',
        'icons_and_actions.status_downtimes',
        'icons_and_actions.status_flapping',
        'icons_and_actions.status_notification_period',
        'icons_and_actions.status_notifications_enabled',
        'icons_and_actions.status_passive_checks',
        'icons_and_actions.status_service_period',
        'icons_and_actions.status_stale',
        'icons_and_actions.wato',
        'icons_and_actions.parent_child_topology',
        'mkeventd.actions',
        'mkeventd.activate',
        'mkeventd.archive_events_of_hosts',
        'mkeventd.changestate',
        'mkeventd.config',
        'mkeventd.delete',
        'mkeventd.edit',
        'mkeventd.see_in_tactical_overview',
        'mkeventd.seeall',
        'mkeventd.seeunrelated',
        'mkeventd.switchmode',
        'mkeventd.update',
        'mkeventd.update_comment',
        'mkeventd.update_contact',
        'nagvis.*_*_*',
        'nagvis.Map_delete',
        'nagvis.Map_delete_*',
        'nagvis.Map_edit',
        'nagvis.Map_edit_*',
        'nagvis.Map_view',
        'nagvis.Map_view_*',
        'nagvis.Rotation_view_*',
        'notification_plugin.asciimail',
        'notification_plugin.cisco_webex_teams',
        'notification_plugin.jira_issues',
        'notification_plugin.mail',
        'notification_plugin.mkeventd',
        'notification_plugin.opsgenie_issues',
        'notification_plugin.pagerduty',
        'notification_plugin.pushover',
        'notification_plugin.servicenow',
        'notification_plugin.slack',
        'notification_plugin.sms',
        'notification_plugin.spectrum',
        'notification_plugin.victorops',
        'sidesnap.about',
        'sidesnap.admin',
        'sidesnap.admin_mini',
        'sidesnap.biaggr_groups',
        'sidesnap.biaggr_groups_tree',
        'sidesnap.bookmarks',
        'sidesnap.custom_links',
        'sidesnap.dashboards',
        'sidesnap.hostgroups',
        'sidesnap.hostmatrix',
        'sidesnap.hosts',
        'sidesnap.master_control',
        'sidesnap.mkeventd_performance',
        'sidesnap.nagios_legacy',
        'sidesnap.nagvis_maps',
        'sidesnap.performance',
        'sidesnap.problem_hosts',
        'sidesnap.search',
        'sidesnap.servicegroups',
        'sidesnap.sitestatus',
        'sidesnap.speedometer',
        'sidesnap.tactical_overview',
        'sidesnap.tag_tree',
        'sidesnap.time',
        'sidesnap.views',
        'sidesnap.wato_folders',
        'sidesnap.wato_foldertree',
        'sidesnap.wiki',
        'view.aggr_all',
        'view.aggr_all_api',
        'view.aggr_group',
        'view.aggr_host',
        'view.aggr_hostgroup_boxed',
        'view.aggr_hostnameaggrs',
        'view.aggr_hostproblems',
        'view.aggr_problems',
        'view.aggr_service',
        'view.aggr_single',
        'view.aggr_single_api',
        'view.aggr_singlehost',
        'view.aggr_singlehosts',
        'view.aggr_summary',
        'view.alerthandlers',
        'view.alertstats',
        'view.allhosts',
        'view.allhosts_mini',
        'view.bi_map_hover_host',
        'view.bi_map_hover_service',
        'view.allservices',
        'view.api_downtimes',
        'view.comments',
        'view.comments_of_host',
        'view.comments_of_service',
        'view.contactnotifications',
        'view.crash_reports',
        'view.downtime_history',
        'view.downtimes',
        'view.downtimes_of_host',
        'view.downtimes_of_service',
        'view.docker_containers',
        'view.docker_nodes',
        'view.vpshere_vms',
        'view.vsphere_servers',
        'view.ec_event',
        'view.ec_event_mobile',
        'view.ec_events',
        'view.ec_events_mobile',
        'view.ec_events_of_host',
        'view.ec_events_of_monhost',
        'view.ec_history_of_event',
        'view.ec_history_of_host',
        'view.ec_history_recent',
        'view.ec_historyentry',
        'view.events',
        'view.events_dash',
        'view.failed_notifications',
        'view.host',
        'view.host_crit',
        'view.host_dt_hist',
        'view.host_export',
        'view.host_ok',
        'view.host_pending',
        'view.host_unknown',
        'view.host_warn',
        'view.hostevents',
        'view.hostgroup',
        'view.hostgroup_up',
        'view.hostgroup_down',
        'view.hostgroup_unreach',
        'view.hostgroup_pend',
        'view.hostgroupgrid',
        'view.hostgroups',
        'view.hostgroupservices',
        'view.hostgroupservices_ok',
        'view.hostgroupservices_warn',
        'view.hostgroupservices_crit',
        'view.hostgroupservices_unknwn',
        'view.hostgroupservices_pend',
        'view.hostnotifications',
        'view.hostpnp',
        'view.hostproblems',
        'view.hostproblems_dash',
        'view.hosts',
        'view.hostsbygroup',
        'view.hoststatus',
        'view.hostsvcevents',
        'view.hostsvcnotifications',
        'view.hosttiles',
        'view.inv_host',
        'view.inv_host_history',
        'view.inv_hosts_cpu',
        'view.inv_hosts_ports',
        'view.invbackplane_of_host',
        'view.invbackplane_search',
        'view.invchassis_of_host',
        'view.invchassis_search',
        'view.invcmksites_of_host',
        'view.invcmksites_search',
        'view.invcmkversions_of_host',
        'view.invcmkversions_search',
        'view.invcontainer_of_host',
        'view.invcontainer_search',
        'view.invdockercontainers_of_host',
        'view.invdockercontainers_search',
        'view.invdockerimages_of_host',
        'view.invdockerimages_search',
        'view.invfan_of_host',
        'view.invfan_search',
        'view.invibmmqchannels_of_host',
        'view.invibmmqchannels_search',
        'view.invibmmqmanagers_of_host',
        'view.invibmmqmanagers_search',
        'view.invibmmqqueues_of_host',
        'view.invibmmqqueues_search',
        'view.invinterface_of_host',
        'view.invinterface_search',
        'view.invkernelconfig_of_host',
        'view.invkernelconfig_search',
        'view.invmodule_of_host',
        'view.invmodule_search',
        'view.invoradataguardstats_of_host',
        'view.invoradataguardstats_search',
        'view.invorainstance_of_host',
        'view.invorainstance_search',
        'view.invorarecoveryarea_of_host',
        'view.invorarecoveryarea_search',
        'view.invorasga_of_host',
        'view.invorasga_search',
        'view.invorapga_of_host',
        'view.invorapga_search',
        'view.invoratablespace_of_host',
        'view.invoratablespace_search',
        'view.invorasystemparameter_of_host',
        'view.invorasystemparameter_search',
        'view.invother_of_host',
        'view.invother_search',
        'view.invpsu_of_host',
        'view.invpsu_search',
        'view.invsensor_of_host',
        'view.invsensor_search',
        'view.invstack_of_host',
        'view.invstack_search',
        'view.invswpac_of_host',
        'view.invswpac_search',
        'view.invtunnels_of_host',
        'view.invtunnels_search',
        'view.invunknown_of_host',
        'view.invunknown_search',
        'view.logfile',
        'view.mobile_contactnotifications',
        'view.mobile_events',
        'view.mobile_host',
        'view.mobile_hostproblems',
        'view.mobile_hostproblems_unack',
        'view.mobile_hoststatus',
        'view.mobile_hostsvcevents',
        'view.mobile_hostsvcnotifications',
        'view.mobile_notifications',
        'view.mobile_searchhost',
        'view.mobile_searchsvc',
        'view.mobile_service',
        'view.mobile_svcevents',
        'view.mobile_svcnotifications',
        'view.mobile_svcproblems',
        'view.mobile_svcproblems_unack',
        'view.nagstamon_hosts',
        'view.nagstamon_svc',
        'view.notifications',
        'view.pending_discovery',
        'view.pendingsvc',
        'view.perf_matrix',
        'view.perf_matrix_search',
        'view.problemsofhost',
        'view.recentsvc',
        'view.searchhost',
        'view.searchpnp',
        'view.searchsvc',
        'view.service',
        'view.service_check_durations',
        'view.servicedesc',
        'view.servicedescpnp',
        'view.servicegroup',
        'view.sitehosts',
        'view.sitesvcs',
        'view.sitesvcs_crit',
        'view.sitesvcs_ok',
        'view.sitesvcs_pend',
        'view.sitesvcs_unknwn',
        'view.sitesvcs_warn',
        'view.stale_hosts',
        'view.starred_hosts',
        'view.starred_services',
        'view.svc_dt_hist',
        'view.svcbygroups',
        'view.svcbyhgroups',
        'view.svcevents',
        'view.svcgroups',
        'view.svcgroups_grid',
        'view.svcnotifications',
        'view.svcproblems',
        'view.svcproblems_dash',
        'view.topology_hover_host',
        'view.topology_filters',
        'view.uncheckedsvc',
        'view.unmonitored_services',
        'wato.activate',
        'wato.activateforeign',
        'wato.add_or_modify_executables',
        'wato.all_folders',
        'wato.analyze_config',
        'wato.api_allowed',
        'wato.auditlog',
        'wato.automation',
        'wato.backups',
        'wato.bi_admin',
        'wato.bi_rules',
        'wato.clear_auditlog',
        'wato.clone_hosts',
        'wato.custom_attributes',
        'wato.diag_host',
        'wato.diagnostics',
        'wato.download_agent_output',
        'wato.download_agents',
        'wato.edit',
        'wato.edit_all_passwords',
        'wato.edit_all_predefined_conditions',
        'wato.edit_folders',
        'wato.edit_hosts',
        'wato.global',
        'wato.groups',
        'wato.hosts',
        'wato.hosttags',
        'wato.icons',
        'wato.manage_folders',
        'wato.manage_hosts',
        'wato.move_hosts',
        'wato.notifications',
        'wato.parentscan',
        'wato.passwords',
        'wato.pattern_editor',
        'wato.random_hosts',
        'wato.rename_hosts',
        'wato.rulesets',
        'wato.see_all_folders',
        'wato.seeall',
        'wato.service_discovery_to_ignored',
        'wato.service_discovery_to_monitored',
        'wato.service_discovery_to_removed',
        'wato.service_discovery_to_undecided',
        'wato.services',
        'wato.set_read_only',
        'wato.sites',
        'wato.snapshots',
        'wato.timeperiods',
        'wato.update_dns_cache',
        'wato.use',
        'wato.users',
        'view.cmk_servers',
        'view.cmk_sites',
        'view.cmk_sites_of_host',
        'dashboard.cmk_overview',
        'dashboard.cmk_host',
        'view.host_graphs',
        'view.service_graphs',
    ]

    if not cmk_version.is_raw_edition():
        expected_permissions += [
            'general.edit_reports',
            'icons_and_actions.agent_deployment',
            'icons_and_actions.status_shadow',
            'report.bi_availability',
            'report.default',
            'report.host',
            'report.instant',
            'report.instant_availability',
            'report.instant_graph_collection',
            'report.instant_view',
            'report.service_availability',
            'report.host_performance_graphs',
            'sidesnap.cmc_stats',
            'sidesnap.reports',
            'view.allhosts_deploy',
            'wato.agent_deploy_custom_files',
            'wato.agent_deployment',
            'wato.agents',
            'wato.alert_handlers',
            'wato.bake_agents',
            'wato.dcd_connections',
            'wato.download_all_agents',
            'wato.manage_mkps',
            'wato.mkps',
            'wato.sign_agents',
            'general.delete_foreign_custom_graph',
            'general.delete_foreign_forecast_graph',
            'general.delete_foreign_graph_collection',
            'general.delete_foreign_graph_tuning',
            'general.delete_foreign_reports',
            'general.delete_foreign_sla_configuration',
            'general.delete_foreign_stored_report',
            'general.delete_stored_report',
            'general.edit_custom_graph',
            'general.edit_forecast_graph',
            'general.edit_foreign_forecast_graph',
            'general.edit_foreign_custom_graph',
            'general.edit_foreign_graph_collection',
            'general.edit_foreign_graph_tuning',
            'general.edit_foreign_reports',
            'general.edit_foreign_sla_configuration',
            'general.edit_graph_collection',
            'general.edit_graph_tuning',
            'general.edit_sla_configuration',
            'general.force_custom_graph',
            'general.publish_forecast_graph',
            'general.force_graph_collection',
            'general.force_graph_tuning',
            'general.publish_graph_collection',
            'general.publish_to_foreign_groups_graph_collection',
            'general.publish_graph_tuning',
            'general.publish_to_foreign_groups_graph_tuning',
            'general.publish_reports',
            'general.publish_reports_to_foreign_groups',
            'general.publish_sla_configuration',
            'general.publish_to_foreign_groups_sla_configuration',
            'general.publish_stored_report',
            'general.publish_to_foreign_groups_forecast_graph',
            'general.see_user_custom_graph',
            'general.see_user_forecast_graph',
            'general.see_user_graph_collection',
            'general.see_user_graph_tuning',
            'general.see_user_reports',
            'general.see_user_sla_configuration',
            'general.see_user_stored_report',
            'general.reporting',
            'general.schedule_reports',
            'general.schedule_reports_all',
            'general.force_forecast_graph',
            'general.force_reports',
            'general.force_sla_configuration',
            'general.instant_reports',
            'general.publish_custom_graph',
            'general.publish_to_foreign_groups_custom_graph',
            'icons_and_actions.deployment_status',
            'icons_and_actions.ntop_host_interface',
            'icons_and_actions.ntop_service_interface',
        ]

    if cmk_version.is_managed_edition():
        expected_permissions += [
            "wato.customer_management",
            "view.customers",
            "view.customer_hosts",
            "view.customer_hosts_up",
            "view.customer_hosts_down",
            "view.customer_hosts_pend",
            "view.customer_hosts_unreach",
            "sidesnap.customers",
        ]

    assert sorted(expected_permissions) == sorted(permission_registry.keys())

    for perm_class in permission_registry.values():
        perm = perm_class()
        assert isinstance(perm.description, str)
        assert isinstance(perm.title, str)
        assert isinstance(perm.defaults, list)
def test_registered_modules():
    expected_modules = [
        "folder",
        "tags",
        "globalvars",
        "host_attrs",
        "wato.py?group=static&mode=rulesets",
        "check_plugins",
        "read_only",
        "predefined_conditions",
        "host_groups",
        "service_groups",
        "users",
        "user_attrs",
        "roles",
        "contact_groups",
        "notifications",
        "timeperiods",
        "mkeventd_rule_packs",
        "bi_packs",
        "sites",
        "backup",
        "passwords",
        "analyze_config",
        "auditlog",
        "icons",
        "background_jobs_overview",
        "ldap_config",
        "diagnostics",
        "download_agents",
        "rule_search",
        "wato.py?group=activechecks&mode=rulesets",
        "wato.py?group=agent&mode=rulesets",
        "wato.py?group=agents&mode=rulesets",
        "wato.py?group=checkparams&mode=rulesets",
        "wato.py?group=custom_checks&mode=rulesets",
        "wato.py?group=datasource_programs&mode=rulesets",
        "wato.py?group=inventory&mode=rulesets",
        "wato.py?group=monconf&mode=rulesets",
        "wato.py?group=host_monconf&mode=rulesets",
        "wato.py?group=snmp&mode=rulesets",
        "wato.py?group=vm_cloud_container&mode=rulesets",
        "wato.py?group=eventconsole&mode=rulesets",
    ]

    if cmk_version.is_raw_edition():
        expected_modules += [
            "download_agents_linux",
            "download_agents_windows",
        ]

    if not cmk_version.is_raw_edition():
        expected_modules += [
            "agent_registration",
            "agents",
            "alert_handlers",
            "dcd_connections",
            "influxdb_connections",
            "license_usage",
            "mkps",
        ]

    if cmk_version.is_managed_edition():
        expected_modules += [
            "customer_management",
        ]

    assert sorted(
        m().mode_or_url
        for m in main_module_registry.values()) == sorted(expected_modules)
Esempio n. 19
0
def expected_items() -> Dict[str, List[str]]:
    agents_items = []

    if cmk_version.is_raw_edition():
        agents_items += [
            'download_agents_linux',
            'download_agents_windows',
        ]
    else:
        agents_items += [
            'agents',
        ]

    agents_items += [
        'download_agents',
        'wato.py?group=vm_cloud_container&mode=rulesets',
        'wato.py?group=datasource_programs&mode=rulesets',
        'wato.py?group=agent&mode=rulesets',
        'wato.py?group=snmp&mode=rulesets',
    ]

    events_items = [
        'notifications',
        'mkeventd_rule_packs',
    ]

    if not cmk_version.is_raw_edition():
        events_items.append('alert_handlers')

    maintenance_items = ['backup']

    if not cmk_version.is_raw_edition():
        maintenance_items.append('license_usage')
        maintenance_items.append('mkps')

    maintenance_items += [
        'diagnostics',
        'analyze_config',
        'background_jobs_overview',
    ]

    hosts_items = [
        'folder',
        'wato.py?group=host_monconf&mode=rulesets',
        'tags',
    ]

    if not cmk_version.is_raw_edition():
        hosts_items.append('dcd_connections')

    hosts_items += [
        'host_groups',
        'host_attrs',
        'wato.py?group=inventory&mode=rulesets',
    ]

    users_items = [
        'users',
        'contact_groups',
        'roles',
        'ldap_config',
        'user_attrs',
    ]

    if cmk_version.is_managed_edition():
        users_items.insert(0, 'customer_management')

    return {
        'agents':
        agents_items,
        'events':
        events_items,
        'general': [
            'rule_search',
            'globalvars',
            'read_only',
            'predefined_conditions',
            'timeperiods',
            'passwords',
            'sites',
            'auditlog',
            'icons',
        ],
        'hosts':
        hosts_items,
        'maintenance':
        maintenance_items,
        'services': [
            'wato.py?group=monconf&mode=rulesets',
            'wato.py?group=checkparams&mode=rulesets',
            'wato.py?group=static&mode=rulesets',
            'wato.py?group=activechecks&mode=rulesets',
            'wato.py?group=custom_checks&mode=rulesets',
            'service_groups',
            'check_plugins',
        ],
        'bi': ['bi_packs'],
        'users':
        users_items,
    }
Esempio n. 20
0
from cmk.utils.livestatus_helpers.queries import Query
from cmk.utils.livestatus_helpers.tables import Hostgroups, Hosts, Servicegroups
from cmk.utils.livestatus_helpers.types import Column, Table

from cmk.gui import sites, watolib
from cmk.gui.exceptions import MKUserError
from cmk.gui.fields.base import BaseSchema, MultiNested, ValueTypedDictSchema
from cmk.gui.fields.utils import attr_openapi_schema, collect_attributes, ObjectContext, ObjectType
from cmk.gui.groups import GroupName, GroupType, load_group_information
from cmk.gui.logged_in import user
from cmk.gui.site_config import allsites
from cmk.gui.watolib.passwords import contact_group_choices, password_exists

from cmk.fields import base, DateTime

if version.is_managed_edition():
    import cmk.gui.cme.managed as managed  # pylint: disable=no-name-in-module


class PythonString(base.String):
    """Represent a Python value expression.

    Any native Python datastructures like tuple, dict, set, etc. can be used.

        Examples:

            >>> expr = PythonString()
            >>> expr.deserialize("{}")
            {}

            >>> expr.deserialize("{'a': (5.5, None)}")
Esempio n. 21
0
def customer_field(**kw):
    if version.is_managed_edition():
        return _CustomerField(**kw)
    return None
Esempio n. 22
0
def _connect_multiple_sites(user: LoggedInUser) -> None:
    enabled_sites, disabled_sites = _get_enabled_and_disabled_sites(user)
    _set_initial_site_states(enabled_sites, disabled_sites)

    if is_managed_edition():
        # Astroid 2.x bug prevents us from using NewType https://github.com/PyCQA/pylint/issues/2296
        import cmk.gui.cme.managed as managed  # pylint: disable=no-name-in-module

        g.live = managed.CMEMultiSiteConnection(enabled_sites, disabled_sites)
    else:
        g.live = MultiSiteConnection(enabled_sites, disabled_sites)

    # Fetch status of sites by querying the version of Nagios and livestatus
    # This may be cached by a proxy for up to the next configuration reload.
    g.live.set_prepend_site(True)
    for response in g.live.query(
            "GET status\n"
            "Cache: reload\n"
            "Columns: livestatus_version program_version program_start num_hosts num_services "
            "core_pid"):

        try:
            site_id, v1, v2, ps, num_hosts, num_services, pid = response
        except ValueError:
            e = MKLivestatusQueryError("Invalid response to status query: %s" %
                                       response)

            site_id = response[0]
            g.site_status[site_id].update({
                "exception":
                e,
                "status_host_state":
                None,
                "state":
                _status_host_state_name(None),
            })
            continue

        g.site_status[site_id].update({
            "state":
            "online",
            "livestatus_version":
            v1,
            "program_version":
            v2,
            "program_start":
            ps,
            "num_hosts":
            num_hosts,
            "num_services":
            num_services,
            "core":
            v2.startswith("Check_MK") and "cmc" or "nagios",
            "core_pid":
            pid,
        })
    g.live.set_prepend_site(False)

    # TODO(lm): Find a better way to make the Livestatus object trigger the update
    # once self.deadsites is updated.
    update_site_states_from_dead_sites()
Esempio n. 23
0
def _get_expected_paths(user_id, is_pre_17_site, with_local):
    expected_paths = [
        "etc",
        "var",
        "etc/check_mk",
        "etc/check_mk/conf.d",
        "etc/check_mk/mkeventd.d",
        "etc/check_mk/multisite.d",
        "etc/check_mk/conf.d/wato",
        "etc/check_mk/conf.d/wato/hosts.mk",
        "etc/check_mk/conf.d/wato/contacts.mk",
        "etc/check_mk/mkeventd.d/wato",
        "etc/check_mk/multisite.d/wato",
        "etc/check_mk/multisite.d/wato/global.mk",
        "var/check_mk",
        "var/check_mk/web",
        "etc/htpasswd",
        "etc/auth.serials",
        "etc/check_mk/multisite.d/wato/users.mk",
        "var/check_mk/web/%s" % user_id,
        "var/check_mk/web/%s/cached_profile.mk" % user_id,
        "var/check_mk/web/%s/enforce_pw_change.mk" % user_id,
        "var/check_mk/web/%s/last_pw_change.mk" % user_id,
        "var/check_mk/web/%s/num_failed_logins.mk" % user_id,
        "var/check_mk/web/%s/serial.mk" % user_id,
    ]

    if with_local:
        expected_paths += [
            "local",
            "var/check_mk/packages",
        ]

    # The new sync directories create all needed files on the central site now
    if not is_pre_17_site:
        expected_paths += [
            "etc/check_mk/apache.d",
            "etc/check_mk/apache.d/wato",
            "etc/check_mk/apache.d/wato/sitespecific.mk",
            "etc/check_mk/conf.d/distributed_wato.mk",
            "etc/check_mk/conf.d/wato/sitespecific.mk",
            "etc/check_mk/mkeventd.d/wato/sitespecific.mk",
            "etc/check_mk/multisite.d/wato/ca-certificates_sitespecific.mk",
            "etc/check_mk/multisite.d/wato/sitespecific.mk",
            "etc/check_mk/rrdcached.d",
            "etc/check_mk/rrdcached.d/wato",
            "etc/check_mk/rrdcached.d/wato/sitespecific.mk",
            "etc/omd",
            "etc/omd/sitespecific.mk",
        ]

        if is_enterprise_repo():
            expected_paths += [
                "etc/check_mk/dcd.d/wato/sitespecific.mk",
                "etc/check_mk/mknotifyd.d/wato/sitespecific.mk",
            ]

        if not cmk_version.is_raw_edition():
            expected_paths += ["etc/check_mk/dcd.d/wato/distributed.mk"]

    # TODO: The second condition should not be needed. Seems to be a subtle difference between the
    # CME and CRE/CEE snapshot logic
    if not cmk_version.is_managed_edition():
        expected_paths += [
            "etc/check_mk/mkeventd.d/mkp",
            "etc/check_mk/mkeventd.d/mkp/rule_packs",
        ]

    # The paths are registered once the enterprise plugins are available, independent of the
    # cmk_version.edition_short() value.
    # TODO: The second condition should not be needed. Seems to be a subtle difference between the
    # CME and CRE/CEE snapshot logic
    if is_enterprise_repo() and (not is_pre_17_site
                                 or not cmk_version.is_managed_edition()):
        expected_paths += [
            "etc/check_mk/dcd.d",
            "etc/check_mk/dcd.d/wato",
            "etc/check_mk/mknotifyd.d",
            "etc/check_mk/mknotifyd.d/wato",
        ]

    # TODO: Shouldn't we clean up these subtle differences?
    if cmk_version.is_managed_edition():
        expected_paths += [
            "etc/check_mk/conf.d/customer.mk",
            "etc/check_mk/conf.d/wato/groups.mk",
            "etc/check_mk/mkeventd.d/wato/rules.mk",
            "etc/check_mk/multisite.d/customer.mk",
            "etc/check_mk/multisite.d/wato/bi.mk",
            "etc/check_mk/multisite.d/wato/customers.mk",
            "etc/check_mk/multisite.d/wato/groups.mk",
            "etc/check_mk/multisite.d/wato/user_connections.mk",
        ]

        expected_paths.remove("etc/check_mk/conf.d/wato/hosts.mk")

    # TODO: The second condition should not be needed. Seems to be a subtle difference between the
    # CME and CRE/CEE snapshot logic
    if not cmk_version.is_raw_edition() and not cmk_version.is_managed_edition(
    ):
        expected_paths += [
            "etc/check_mk/liveproxyd.d",
            "etc/check_mk/liveproxyd.d/wato",
        ]

    return expected_paths
Esempio n. 24
0
def test_registered_modules():
    expected_modules = [
        'folder',
        'tags',
        'globalvars',
        'host_attrs',
        'wato.py?mode=rulesets&group=static',
        'check_plugins',
        'read_only',
        'predefined_conditions',
        'host_groups',
        'service_groups',
        'users',
        'user_attrs',
        'roles',
        'contact_groups',
        'notifications',
        'timeperiods',
        'mkeventd_rule_packs',
        'bi_packs',
        'sites',
        'backup',
        'passwords',
        'analyze_config',
        'auditlog',
        'icons',
        'background_jobs_overview',
        'ldap_config',
        'diagnostics',
        'download_agents',
        'version.py',
        'rule_search',
        'wato.py?mode=rulesets&group=activechecks',
        'wato.py?mode=rulesets&group=agent',
        'wato.py?mode=rulesets&group=checkparams',
        'wato.py?mode=rulesets&group=custom_checks',
        'wato.py?mode=rulesets&group=custom_integrations',
        'wato.py?mode=rulesets&group=datasource_programs',
        'wato.py?mode=rulesets&group=inventory',
        'wato.py?mode=rulesets&group=monconf',
        'wato.py?mode=rulesets&group=host_monconf',
        'wato.py?mode=rulesets&group=snmp',
        'wato.py?mode=rulesets&group=vm_cloud_container',
    ]

    if cmk_version.is_raw_edition():
        expected_modules += [
            'download_agents_linux',
            'download_agents_windows',
        ]

    if not cmk_version.is_raw_edition():
        expected_modules += [
            'agents',
            'alert_handlers',
            'mkps',
            'license_usage',
            'dcd_connections',
        ]

    if cmk_version.is_managed_edition():
        expected_modules += [
            "customer_management",
        ]

    module_names = [m.mode_or_url for m in main_menu.get_modules()]
    assert sorted(module_names) == sorted(expected_modules)
Esempio n. 25
0
# -*- coding: utf-8 -*-
# Copyright (C) 2020 tribe29 GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

import json
import random
import string

import pytest

from cmk.utils import version

from tests.unit.cmk.gui.conftest import WebTestAppForCMK

managedtest = pytest.mark.skipif(not version.is_managed_edition(), reason="see #7213")


@managedtest
@pytest.mark.parametrize("group_type", ["host", "contact", "service"])
def test_openapi_groups(group_type, aut_user_auth_wsgi_app: WebTestAppForCMK):

    name = _random_string(10)
    alias = _random_string(10)

    group = {"name": name, "alias": alias, "customer": "provider"}

    base = "/NO_SITE/check_mk/api/1.0"
    resp = aut_user_auth_wsgi_app.call_method(
        "post",
        base + f"/domain-types/{group_type}_group_config/collections/all",
Esempio n. 26
0
    def action(self):
        if not html.check_transaction():
            return "users"

        if self._user_id is None:  # same as self._is_new_user
            self._user_id = UserID(allow_empty=False).from_html_vars("user_id")
            user_attrs = {}
        else:
            self._user_id = html.request.get_unicode_input_mandatory(
                "edit").strip()
            user_attrs = self._users[UserId(self._user_id)]

        # Full name
        user_attrs["alias"] = html.request.get_unicode_input_mandatory(
            "alias").strip()

        # Locking
        user_attrs["locked"] = html.get_checkbox("locked")
        increase_serial = False

        if (UserId(self._user_id) in self._users and self._users[UserId(
                self._user_id)]["locked"] != user_attrs["locked"]
                and user_attrs["locked"]):
            increase_serial = True  # when user is being locked now, increase the auth serial

        # Authentication: Password or Secret
        auth_method = html.request.var("authmethod")
        if auth_method == "secret":
            secret = html.request.get_str_input_mandatory("_auth_secret",
                                                          "").strip()
            user_attrs["automation_secret"] = secret
            user_attrs["password"] = hash_password(secret)
            increase_serial = True  # password changed, reflect in auth serial

        else:
            password = html.request.get_str_input_mandatory(
                "_password_" + self._pw_suffix(), '').strip()
            password2 = html.request.get_str_input_mandatory(
                "_password2_" + self._pw_suffix(), '').strip()

            # We compare both passwords only, if the user has supplied
            # the repeation! We are so nice to our power users...
            # Note: this validation is done before the main-validiation later on
            # It doesn't make any sense to put this block into the main validation function
            if password2 and password != password2:
                raise MKUserError("_password2",
                                  _("The both passwords do not match."))

            # Detect switch back from automation to password
            if "automation_secret" in user_attrs:
                del user_attrs["automation_secret"]
                if "password" in user_attrs:
                    del user_attrs[
                        "password"]  # which was the encrypted automation password!

            if password:
                user_attrs["password"] = hash_password(password)
                user_attrs["last_pw_change"] = int(time.time())
                increase_serial = True  # password changed, reflect in auth serial

            # PW change enforcement
            user_attrs["enforce_pw_change"] = html.get_checkbox(
                "enforce_pw_change")
            if user_attrs["enforce_pw_change"]:
                increase_serial = True  # invalidate all existing user sessions, enforce relogon

        # Increase serial (if needed)
        if increase_serial:
            user_attrs["serial"] = user_attrs.get("serial", 0) + 1

        # Email address
        user_attrs["email"] = EmailAddress().from_html_vars("email")

        idle_timeout = watolib.get_vs_user_idle_timeout().from_html_vars(
            "idle_timeout")
        user_attrs["idle_timeout"] = idle_timeout
        if idle_timeout is not None:
            user_attrs["idle_timeout"] = idle_timeout
        elif idle_timeout is None and "idle_timeout" in user_attrs:
            del user_attrs["idle_timeout"]

        # Pager
        user_attrs["pager"] = html.request.get_str_input_mandatory(
            "pager", '').strip()

        if cmk_version.is_managed_edition():
            customer = self._vs_customer.from_html_vars("customer")
            self._vs_customer.validate_value(customer, "customer")

            if customer != managed.default_customer_id():
                user_attrs["customer"] = customer
            elif "customer" in user_attrs:
                del user_attrs["customer"]

        vs_sites = self._vs_sites()
        authorized_sites = vs_sites.from_html_vars("authorized_sites")
        vs_sites.validate_value(authorized_sites, "authorized_sites")

        if authorized_sites is not None:
            user_attrs["authorized_sites"] = authorized_sites
        elif "authorized_sites" in user_attrs:
            del user_attrs["authorized_sites"]

        # Roles
        user_attrs["roles"] = [
            role for role in self._roles.keys()
            if html.get_checkbox("role_" + role)
        ]

        # Language configuration
        set_lang = html.get_checkbox("_set_lang")
        language = html.request.var("language")
        if set_lang:
            if language == "":
                language = None
            user_attrs["language"] = language
        elif not set_lang and "language" in user_attrs:
            del user_attrs["language"]

        # Contact groups
        cgs = []
        for c in self._contact_groups:
            if html.get_checkbox("cg_" + c):
                cgs.append(c)
        user_attrs["contactgroups"] = cgs

        # Notification settings are only active if we do *not* have
        # rule based notifications!
        if not self._rbn_enabled():
            # Notifications
            user_attrs["notifications_enabled"] = html.get_checkbox(
                "notifications_enabled")

            ntp = html.request.var("notification_period")
            if ntp not in self._timeperiods:
                ntp = "24X7"
            user_attrs["notification_period"] = ntp

            for what, opts in [("host", "durfs"), ("service", "wucrfs")]:
                user_attrs[what + "_notification_options"] = "".join([
                    opt for opt in opts if html.get_checkbox(what + "_" + opt)
                ])

            value = watolib.get_vs_flexible_notifications().from_html_vars(
                "notification_method")
            user_attrs["notification_method"] = value
        else:
            user_attrs["fallback_contact"] = html.get_checkbox(
                "fallback_contact")

        # Custom user attributes
        for name, attr in userdb.get_user_attributes():
            value = attr.valuespec().from_html_vars('ua_' + name)
            user_attrs[name] = value

        # Generate user "object" to update
        user_object = {
            self._user_id: {
                "attributes": user_attrs,
                "is_new_user": self._is_new_user
            }
        }
        # The following call validates and updated the users
        edit_users(user_object)
        return "users"
Esempio n. 27
0
def _expected_replication_paths():
    expected = [
        ReplicationPath("dir", "check_mk", "etc/check_mk/conf.d/wato/", []),
        ReplicationPath("dir", "multisite", "etc/check_mk/multisite.d/wato/",
                        []),
        ReplicationPath("file", "htpasswd", "etc/htpasswd", []),
        ReplicationPath("file", "auth.secret", "etc/auth.secret", []),
        ReplicationPath("file", "password_store.secret",
                        "etc/password_store.secret", []),
        ReplicationPath("file", "auth.serials", "etc/auth.serials", []),
        ReplicationPath("file", "stored_passwords",
                        "var/check_mk/stored_passwords", []),
        ReplicationPath("dir", "usersettings", "var/check_mk/web",
                        ["report-thumbnails", "session_info.mk"]),
        ReplicationPath("dir", "mkps", "var/check_mk/packages", []),
        ReplicationPath("dir", "local", "local", []),
    ]

    if not cmk_version.is_raw_edition():
        expected += [
            ReplicationPath("dir", "liveproxyd",
                            "etc/check_mk/liveproxyd.d/wato/", []),
        ]

    if testlib.is_enterprise_repo():
        expected += [
            ReplicationPath("dir", "dcd", "etc/check_mk/dcd.d/wato/", []),
            ReplicationPath("dir", "mknotify", "etc/check_mk/mknotifyd.d/wato",
                            []),
        ]

    expected += [
        ReplicationPath("dir", "mkeventd", "etc/check_mk/mkeventd.d/wato", []),
        ReplicationPath("dir", "mkeventd_mkp",
                        "etc/check_mk/mkeventd.d/mkp/rule_packs", []),
        ReplicationPath("file", "diskspace", "etc/diskspace.conf", []),
    ]

    if cmk_version.is_managed_edition():
        expected += [
            ReplicationPath(
                ty="file",
                ident="customer_check_mk",
                site_path="etc/check_mk/conf.d/customer.mk",
                excludes=[],
            ),
            ReplicationPath(
                ty="file",
                ident="customer_gui_design",
                site_path="etc/check_mk/multisite.d/zzz_customer_gui_design.mk",
                excludes=[],
            ),
            ReplicationPath(
                ty="file",
                ident="customer_multisite",
                site_path="etc/check_mk/multisite.d/customer.mk",
                excludes=[],
            ),
            ReplicationPath(
                ty="file",
                ident="gui_logo",
                site_path=
                "local/share/check_mk/web/htdocs/themes/classic/images/sidebar_top.png",
                excludes=[],
            ),
            ReplicationPath(
                ty="file",
                ident="gui_logo_dark",
                site_path=
                "local/share/check_mk/web/htdocs/themes/modern-dark/images/mk-logo.png",
                excludes=[],
            ),
            ReplicationPath(
                ty="file",
                ident="gui_logo_facelift",
                site_path=
                "local/share/check_mk/web/htdocs/themes/facelift/images/mk-logo.png",
                excludes=[],
            ),
        ]

    return expected
Esempio n. 28
0
import contextlib
import json
import http.client

from typing import Any, Dict, Literal, Sequence, List, Optional, Type, Union, Tuple

from cmk.gui.http import Response
from cmk.gui.groups import load_group_information, GroupSpecs, GroupSpec
from cmk.gui.plugins.openapi.restful_objects import constructors
from cmk.gui.plugins.openapi.utils import ProblemException
from cmk.gui.watolib import CREFolder
from cmk.gui.watolib.groups import edit_group, GroupType
from cmk.utils import version

from cmk.utils.version import is_managed_edition
if is_managed_edition():
    import cmk.gui.cme.managed as managed  # pylint: disable=no-name-in-module


GroupName = Literal[
    'host_group_config',
    'contact_group_config',
    'service_group_config',
    'agent'
]  # yapf: disable


def complement_customer(details):
    if not is_managed_edition():
        return details
Esempio n. 29
0
    NEGATE,
    wato_root_dir,
    multisite_dir,
    rename_host_in_list,
    convert_cgroups_from_tuple,
    host_attribute_matches,
    default_site,
    format_config_value,
    liveproxyd_config_dir,
    mk_repr,
    mk_eval,
    has_agent_bakery,
    site_neutral_path,
)
from cmk.gui.watolib.wato_background_job import WatoBackgroundJob
if cmk_version.is_managed_edition():
    import cmk.gui.cme.managed as managed  # pylint: disable=no-name-in-module

from cmk.gui.plugins.watolib.utils import (
    ABCConfigDomain,
    config_domain_registry,
    config_variable_registry,
    wato_fileheader,
    SampleConfigGenerator,
    sample_config_generator_registry,
)

import cmk.gui.plugins.watolib

if not cmk_version.is_raw_edition():
    import cmk.gui.cee.plugins.watolib  # pylint: disable=no-name-in-module
Esempio n. 30
0
    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" %
                        six.ensure_str(base64.b64encode(uid.encode("utf-8"))))

                user_connection_id = cleanup_connection_id(
                    user.get('connector'))
                connection = 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_version.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(timeperiod_spec_alias(
                                timeperiods[tp], tp),
                                               href=url)
                        else:
                            tp = timeperiod_spec_alias(timeperiods[tp], tp)
                        html.write(tp)

                # the visible custom attributes
                for name, attr in visible_custom_attrs:
                    vs = attr.valuespec()
                    table.cell(escaping.escape_attribute(_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()