Module: check_mk
Branch: master
Commit: 5d5d6f273cb5487bf75852d15936b1c0e0be912d
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=5d5d6f273cb548…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Thu Jun 29 10:04:52 2017 +0200
4921 Users can be limited to a list of authorized sites now
It is now possible to configure a list of authorized sites for each user.
This is especially useful when having a huge number of sites configured,
like several hundred, in a distributed setup. In case you have users that
have their hosts on only some of these sites, you can set the new authorized
sites option for these users.
For the users that have authorized sites configured the GUI will only contact
these sites instead of all sites to build up their views. In large environments
this will be a huge performance improvement.
Change-Id: I428928d99714dda7dffa2a668cd63b67830ce610
---
.werks/4921 | 19 +++++++++++++++++++
web/htdocs/config.py | 19 +++++++++++++++++--
web/htdocs/sites.py | 11 ++++++-----
web/htdocs/valuespec.py | 20 ++++++++++++++++++--
web/htdocs/wato.py | 37 +++++++++++++++++++++++++++++++++++++
web/htdocs/watolib.py | 2 +-
6 files changed, 98 insertions(+), 10 deletions(-)
diff --git a/.werks/4921 b/.werks/4921
new file mode 100644
index 0000000..a94cec0
--- /dev/null
+++ b/.werks/4921
@@ -0,0 +1,19 @@
+Title: Users can be limited to a list of authorized sites now
+Level: 2
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.5.0i1
+Date: 1498723224
+Class: feature
+
+It is now possible to configure a list of authorized sites for each user.
+
+This is especially useful when having a huge number of sites configured,
+like several hundred, in a distributed setup. In case you have users that
+have their hosts on only some of these sites, you can set the new authorized
+sites option for these users.
+
+For the users that have authorized sites configured the GUI will only contact
+these sites instead of all sites to build up their views. In large environments
+this will be a huge performance improvement.
diff --git a/web/htdocs/config.py b/web/htdocs/config.py
index 03e15eb..92ecb65 100644
--- a/web/htdocs/config.py
+++ b/web/htdocs/config.py
@@ -428,6 +428,21 @@ class LoggedInUser(object):
self.save_file("favorites", list(stars))
+ def is_site_disabled(self, site_id):
+ siteconf = self.siteconf.get(site_id, {})
+ return siteconf.get("disabled", False)
+
+
+ def authorized_sites(self):
+ authorized_sites = self.get_attribute("authorized_sites")
+ all_sites = allsites()
+ if authorized_sites is None:
+ return all_sites
+ else:
+ return dict([ (site_id, site) for site_id, site in all_sites.items()
+ if site_id in authorized_sites ])
+
+
def may(self, pname):
if pname in self.permissions:
return self.permissions[pname]
@@ -660,8 +675,8 @@ def configured_sites():
def sorted_sites():
sitenames = []
- for sitename, site in allsites().iteritems():
- sitenames.append((sitename, site['alias']))
+ for site_id, site in user.authorized_sites().items():
+ sitenames.append((site_id, site['alias']))
sitenames = sorted(sitenames, key=lambda k: k[1], cmp = lambda a,b: cmp(a.lower(),
b.lower()))
return sitenames
diff --git a/web/htdocs/sites.py b/web/htdocs/sites.py
index 4383fcd..e26c9e9 100644
--- a/web/htdocs/sites.py
+++ b/web/htdocs/sites.py
@@ -186,12 +186,13 @@ def _connect_multiple_sites():
def _get_enabled_and_disabled_sites():
enabled_sites, disabled_sites = {}, {}
- for site_id, site in config.allsites().items():
- siteconf = config.user.siteconf.get(site_id, {})
- if siteconf.get("disabled", False):
- disabled_sites[site_id] = site
+ for site_id, site in config.user.authorized_sites().items():
+ if config.user.is_site_disabled(site_id):
+ sites = disabled_sites
else:
- enabled_sites[site_id] = site
+ sites = enabled_sites
+
+ sites[site_id] = site
return enabled_sites, disabled_sites
diff --git a/web/htdocs/valuespec.py b/web/htdocs/valuespec.py
index 6a2701e..1b652d6 100644
--- a/web/htdocs/valuespec.py
+++ b/web/htdocs/valuespec.py
@@ -2022,6 +2022,7 @@ class ListChoice(ValueSpec):
# Make sure that at least one variable with the prefix is present
html.hidden_field(varprefix, "1", add_var=True)
+
def value_to_text(self, value):
self.load_elements()
d = dict(self._elements)
@@ -2033,6 +2034,7 @@ class ListChoice(ValueSpec):
return "%s" %
html.render_table(html.render_tr(html.render_td(html.render_br().join( map(lambda x:
HTML(x), texts) ))))
#OLD: return "<table><tr><td>" +
"<br>".join(texts) + "</td></tr></table>"
+
def from_html_vars(self, varprefix):
self.load_elements()
value = []
@@ -2042,20 +2044,30 @@ class ListChoice(ValueSpec):
value.append(key)
return value
+
def validate_datatype(self, value, varprefix):
self.load_elements()
+
if type(value) != list:
raise MKUserError(varprefix, _("The datatype must be list, but is
%s") % type_name(value))
- d = dict(self._elements)
+
for v in value:
- if v not in d:
+ if self._value_is_invalid(v):
raise MKUserError(varprefix, _("%s is not an allowed value") %
v)
+
def validate_value(self, value, varprefix):
if not self._allow_empty and not value:
raise MKUserError(varprefix, _('You have to select at least one
element.'))
ValueSpec.custom_validate(self, value, varprefix)
+
+ def _value_is_invalid(self, value):
+ d = dict(self._elements)
+ return value not in d
+
+
+
# A alternative way of editing list choices
class MultiSelect(ListChoice):
def __init__(self, **kwargs):
@@ -2118,6 +2130,10 @@ class DualListChoice(ListChoice):
html.write_text(_("There are no elements for selection."))
return
+ # Use values from HTTP request in complain mode
+ if value is None:
+ value = self.from_html_vars(varprefix)
+
selected = []
unselected = []
if self._custom_order:
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index d9c7d7f..91b338d 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -10370,6 +10370,10 @@ def mode_users(phase):
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
load_configuration_settings().get("enable_rulebased_notifications"):
table.cell(_("Notifications"))
@@ -10501,6 +10505,8 @@ def mode_edit_user(phase):
if cmk.is_managed_edition():
vs_customer = managed.vs_customer()
+ vs_sites = vs_authorized_sites()
+
if phase == "action":
if not html.check_transaction():
return "users"
@@ -10583,6 +10589,14 @@ def mode_edit_user(phase):
elif "customer" in user_attrs:
del user_attrs["customer"]
+ 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"] = filter(lambda role:
html.get_checkbox("role_" + role),
roles.keys())
@@ -10687,6 +10701,11 @@ def mode_edit_user(phase):
html.help(vs_customer.help())
+ forms.section(vs_sites.title())
+ vs_sites.render_input("authorized_sites",
+ user.get("authorized_sites", vs_sites.default_value()))
+ html.help(vs_sites.help())
+
custom_user_attributes('ident')
forms.header(_("Security"))
@@ -10926,6 +10945,24 @@ def mode_edit_user(phase):
html.end_form()
+def vs_authorized_sites():
+ return Alternative(
+ title = _("Authorized sites"),
+ help = _("The sites the user is authorized to see in the GUI."),
+ default_value = None,
+ style = "dropdown",
+ elements = [
+ FixedValue(None,
+ title = _("All sites"),
+ totext = _("May see all sites"),
+ ),
+ DualListChoice(
+ title = _("Specific sites"),
+ choices = config.site_choices,
+ ),
+ ],
+ )
+
def generate_wato_users_elements_function(none_value, only_contacts = False):
def get_wato_users(nv):
diff --git a/web/htdocs/watolib.py b/web/htdocs/watolib.py
index 8bf310c..fbf56ea 100644
--- a/web/htdocs/watolib.py
+++ b/web/htdocs/watolib.py
@@ -4473,7 +4473,7 @@ class ActivateChanges(object):
# these sites are shown on activation page and get change entries
# added during WATO changes.
def _activation_sites(self):
- return [ (site_id, site) for site_id, site in config.configured_sites()
+ return [ (site_id, site) for site_id, site in
config.user.authorized_sites().items()
if config.site_is_local(site_id)
or site.get("replication") ]