Example #1
0
def _add_group_change(group: GroupSpec, action_name: str, text: str) -> None:
    group_sites = None
    if cmk_version.is_managed_edition():
        cid = managed.get_customer_id(group)
        if not managed.is_global(cid):
            if cid is None:  # conditional caused by bad typing
                raise Exception("cannot happen: no customer ID")
            group_sites = list(managed.get_sites_of_customer(cid).keys())

    add_change(action_name, text, sites=group_sites)
Example #2
0
def edit_group(name: GroupName, group_type: GroupType,
               extra_info: GroupSpec) -> None:
    _check_modify_group_permissions(group_type)
    all_groups = load_group_information()
    groups = all_groups.get(group_type, {})

    if name not in groups:
        raise MKUserError("name", _("Unknown group: %s") % name)

    old_group_backup = copy.deepcopy(groups[name])

    _set_group(all_groups, group_type, name, extra_info)
    if cmk_version.is_managed_edition():
        old_customer = managed.get_customer_id(old_group_backup)
        new_customer = managed.get_customer_id(extra_info)
        if old_customer != new_customer:
            _add_group_change(
                old_group_backup,
                "edit-%sgroups" % group_type,
                _("Removed %sgroup %s from customer %s") %
                (group_type, name,
                 managed.get_customer_name_by_id(old_customer)),
            )
            _add_group_change(
                extra_info,
                "edit-%sgroups" % group_type,
                _("Moved %sgroup %s to customer %s. Additional properties may have changed."
                  ) % (group_type, name,
                       managed.get_customer_name_by_id(new_customer)),
            )
        else:
            _add_group_change(
                old_group_backup,
                "edit-%sgroups" % group_type,
                _("Updated properties of %sgroup %s") % (group_type, name),
            )
    else:
        _add_group_change(
            extra_info,
            "edit-%sgroups" % group_type,
            _("Updated properties of %s group %s") % (group_type, name),
        )
Example #3
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
Example #4
0
def _add_group_change(group, action_name, text):
    group_sites = None
    if cmk.is_managed_edition() and not managed.is_global(managed.get_customer_id(group)):
        group_sites = managed.get_sites_of_customer(managed.get_customer_id(group))

    add_change(action_name, text, sites=group_sites)
Example #5
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"):
            EmailAddressUnicode().render_input("email", email)
        else:
            html.write_text(email)
            html.hidden_field("email", email)

        html.help(
            _("The email address is optional and is needed "
              "if the user is a monitoring contact and receives notifications "
              "via Email."))

        forms.section(_("Pager address"))
        lockable_input('pager', '')
        html.help(_("The pager address is optional "))

        if cmk.is_managed_edition():
            forms.section(self._vs_customer.title())
            self._vs_customer.render_input("customer", managed.get_customer_id(self._user))

            html.help(self._vs_customer.help())

        vs_sites = self._vs_sites()
        forms.section(vs_sites.title())
        authorized_sites = self._user.get("authorized_sites", vs_sites.default_value())
        if not self._is_locked("authorized_sites"):
            vs_sites.render_input("authorized_sites", authorized_sites)
        else:
            html.write_html(vs_sites.value_to_text(authorized_sites))
        html.help(vs_sites.help())

        self._show_custom_user_attributes('ident')

        forms.header(_("Security"))
        forms.section(_("Authentication"))

        is_automation = self._user.get("automation_secret", None) is not None
        html.radiobutton("authmethod", "password", not is_automation,
                         _("Normal user login with password"))
        html.open_ul()
        html.open_table()
        html.open_tr()
        html.td(_("password:"******"_password_" + self._pw_suffix(), autocomplete="new-password")
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.td(_("repeat:"))
            html.open_td()
            html.password_input("_password2_" + self._pw_suffix(), autocomplete="new-password")
            html.write_text(" (%s)" % _("optional"))
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.td("%s:" % _("Enforce change"))
            html.open_td()
            # Only make password enforcement selection possible when user is allowed to change the PW
            if self._is_new_user or config.user_may(self._user_id,
                                                    'general.edit_profile') and config.user_may(
                                                        self._user_id, 'general.change_password'):
                html.checkbox("enforce_pw_change",
                              self._user.get("enforce_pw_change", False),
                              label=_("Change password at next login or access"))
            else:
                html.write_text(
                    _("Not permitted to change the password. Change can not be enforced."))
        else:
            html.i(_('The password can not be changed (It is locked by the user connector).'))
            html.hidden_field('_password', '')
            html.hidden_field('_password2', '')

        html.close_td()
        html.close_tr()
        html.close_table()
        html.close_ul()

        html.radiobutton("authmethod", "secret", is_automation,
                         _("Automation secret for machine accounts"))

        html.open_ul()
        html.text_input("_auth_secret",
                        self._user.get("automation_secret", ""),
                        size=30,
                        id_="automation_secret")
        html.write_text(" ")
        html.open_b(style=["position: relative", "top: 4px;"])
        html.write(" &nbsp;")
        html.icon_button("javascript:cmk.wato.randomize_secret('automation_secret', 20);",
                         _("Create random secret"), "random")
        html.close_b()
        html.close_ul()

        html.help(
            _("If you want the user to be able to login "
              "then specify a password here. Users without a login make sense "
              "if they are monitoring contacts that are just used for "
              "notifications. The repetition of the password is optional. "
              "<br>For accounts used by automation processes (such as fetching "
              "data from views for further procession), set the method to "
              "<u>secret</u>. The secret will be stored in a local file. Processes "
              "with read access to that file will be able to use Multisite as "
              "a webservice without any further configuration."))

        # Locking
        forms.section(_("Disable password"), simple=True)
        if not self._is_locked('locked'):
            html.checkbox("locked",
                          self._user.get("locked", False),
                          label=_("disable the login to this account"))
        else:
            html.write_text(
                _('Login disabled') if self._user.get("locked", False) else _('Login possible'))
            html.hidden_field('locked', '1' if self._user.get("locked", False) else '')
        html.help(
            _("Disabling the password will prevent a user from logging in while "
              "retaining the original password. Notifications are not affected "
              "by this setting."))

        forms.section(_("Idle timeout"))
        idle_timeout = self._user.get("idle_timeout")
        if not self._is_locked("idle_timeout"):
            watolib.get_vs_user_idle_timeout().render_input("idle_timeout", idle_timeout)
        else:
            html.write_text(idle_timeout)
            html.hidden_field("idle_timeout", idle_timeout)

        # Roles
        forms.section(_("Roles"))
        entries = self._roles.items()
        entries.sort(key=lambda x: (x[1]["alias"], x[0]))
        is_member_of_at_least_one = False
        for role_id, role in entries:
            if not self._is_locked("roles"):
                html.checkbox("role_" + role_id, role_id in self._user.get("roles", []))
                url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)])
                html.a(role["alias"], href=url)
                html.br()
            else:
                is_member = role_id in self._user.get("roles", [])
                if is_member:
                    is_member_of_at_least_one = True
                    url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)])
                    html.a(role["alias"], href=url)
                    html.br()

                html.hidden_field("role_" + role_id, '1' if is_member else '')
        if self._is_locked('roles') and not is_member_of_at_least_one:
            html.i(_('No roles assigned.'))
        self._show_custom_user_attributes('security')

        # Contact groups
        forms.header(_("Contact Groups"), isopen=False)
        forms.section()
        groups_page_url = watolib.folder_preserving_link([("mode", "contact_groups")])
        group_assign_url = watolib.folder_preserving_link([("mode", "rulesets"),
                                                           ("group", "grouping")])
        if not self._contact_groups:
            html.write(
                _("Please first create some <a href='%s'>contact groups</a>") % groups_page_url)
        else:
            entries = sorted([(group['alias'] or c, c) for c, group in self._contact_groups.items()
                             ])
            is_member_of_at_least_one = False
            for alias, gid in entries:
                is_member = gid in self._user.get("contactgroups", [])

                if not self._is_locked('contactgroups'):
                    html.checkbox("cg_" + gid, gid in self._user.get("contactgroups", []))
                else:
                    if is_member:
                        is_member_of_at_least_one = True
                    html.hidden_field("cg_" + gid, '1' if is_member else '')

                if not self._is_locked('contactgroups') or is_member:
                    url = watolib.folder_preserving_link([("mode", "edit_contact_group"),
                                                          ("edit", gid)])
                    html.a(alias, href=url)
                    html.br()

            if self._is_locked('contactgroups') and not is_member_of_at_least_one:
                html.i(_('No contact groups assigned.'))

        html.help(
            _("Contact groups are used to assign monitoring "
              "objects to users. If you haven't defined any contact groups yet, "
              "then first <a href='%s'>do so</a>. Hosts and services can be "
              "assigned to contact groups using <a href='%s'>rules</a>.<br><br>"
              "If you do not put the user into any contact group "
              "then no monitoring contact will be created for the user.") %
            (groups_page_url, group_assign_url))

        forms.header(_("Notifications"), isopen=False)
        if not self._rbn_enabled():
            forms.section(_("Enabling"), simple=True)
            html.checkbox("notifications_enabled",
                          self._user.get("notifications_enabled", False),
                          label=_("enable notifications"))
            html.help(
                _("Notifications are sent out "
                  "when the status of a host or service changes."))

            # Notification period
            forms.section(_("Notification time period"))
            choices = [(id_, "%s" % (tp["alias"])) for (id_, tp) in self._timeperiods.items()]
            html.dropdown("notification_period",
                          choices,
                          deflt=self._user.get("notification_period"),
                          ordered=True)
            html.help(
                _("Only during this time period the "
                  "user will get notifications about host or service alerts."))

            # Notification options
            notification_option_names = {  # defined here: _() must be executed always!
                "host": {
                    "d": _("Host goes down"),
                    "u": _("Host gets unreachble"),
                    "r": _("Host goes up again"),
                },
                "service": {
                    "w": _("Service goes into warning state"),
                    "u": _("Service goes into unknown state"),
                    "c": _("Service goes into critical state"),
                    "r": _("Service recovers to OK"),
                },
                "both": {
                    "f": _("Start or end of flapping state"),
                    "s": _("Start or end of a scheduled downtime"),
                }
            }

            forms.section(_("Notification Options"))
            for title, what, opts in [(_("Host events"), "host", "durfs"),
                                      (_("Service events"), "service", "wucrfs")]:
                html.write_text("%s:" % title)
                html.open_ul()

                user_opts = self._user.get(what + "_notification_options", opts)
                for opt in opts:
                    opt_name = notification_option_names[what].get(
                        opt, notification_option_names["both"].get(opt))
                    html.checkbox(what + "_" + opt, opt in user_opts, label=opt_name)
                    html.br()
                html.close_ul()

            html.help(
                _("Here you specify which types of alerts "
                  "will be notified to this contact. Note: these settings will only be saved "
                  "and used if the user is member of a contact group."))

            forms.section(_("Notification Method"))
            watolib.get_vs_flexible_notifications().render_input(
                "notification_method", self._user.get("notification_method"))

        else:
            forms.section(_("Fallback notifications"), simple=True)

            html.checkbox("fallback_contact",
                          self._user.get("fallback_contact", False),
                          label=_("Receive fallback notifications"))

            html.help(
                _("In case none of your notification rules handles a certain event a notification "
                  "will be sent to this contact. This makes sure that in that case at least <i>someone</i> "
                  "gets notified. Furthermore this contact will be used for notifications to any host or service "
                  "that is not known to the monitoring. This can happen when you forward notifications "
                  "from the Event Console.<br><br>Notification fallback can also configured in the global "
                  "setting <a href=\"wato.py?mode=edit_configvar&varname=notification_fallback_email\">"
                  "Fallback email address for notifications</a>."))

        self._show_custom_user_attributes('notify')

        forms.header(_("Personal Settings"), isopen=False)
        select_language(self._user)
        self._show_custom_user_attributes('personal')

        # Later we could add custom macros here, which then could be used
        # for notifications. On the other hand, if we implement some check_mk
        # --notify, we could directly access the data in the account with the need
        # to store values in the monitoring core. We'll see what future brings.
        forms.end()
        html.button("save", _("Save"))
        if self._is_new_user:
            html.set_focus("user_id")
        else:
            html.set_focus("alias")
        html.hidden_fields()
        html.end_form()