Module: check_mk
Branch: master
Commit: acbdf576d8af190a59b202aa3588a4e299369eaf
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=acbdf576d8af19…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Mon Feb 26 11:14:33 2018 +0100
5866 FIX Fixed performance issue on ruleset search and discovery page with a large number
of rules
When rule matching was analyzed in WATO, which is done for example on the ruleset rule
listing
page, on the analyze rulset page of hosts or on the service discovery page, a time
consuming
match function needs to be called. This function has now been optimizied which should
result in
a more performant processing of these pages with a larger number of rules.
Change-Id: Ib6dc8fcf9b26a573f6aa8aacb260d97322383070
---
.werks/5866 | 13 +++++++++++++
web/htdocs/wato.py | 42 +++++++++++++++++++++---------------------
web/htdocs/watolib.py | 31 ++++++++++++++++---------------
3 files changed, 50 insertions(+), 36 deletions(-)
diff --git a/.werks/5866 b/.werks/5866
new file mode 100644
index 0000000..459fd67
--- /dev/null
+++ b/.werks/5866
@@ -0,0 +1,13 @@
+Title: Fixed performance issue on ruleset search and discovery page with a large number
of rules
+Level: 1
+Component: wato
+Compatible: compat
+Edition: cre
+Version: 1.5.0i4
+Date: 1519639736
+Class: fix
+
+When rule matching was analyzed in WATO, which is done for example on the ruleset rule
listing
+page, on the analyze rulset page of hosts or on the service discovery page, a time
consuming
+match function needs to be called. This function has now been optimizied which should
result in
+a more performant processing of these pages with a larger number of rules.
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index a2a6858..d41233c 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -13158,12 +13158,14 @@ class ModeEditRuleset(WatoMode):
if self._hostname:
table.cell(_("Ma."))
if rule.is_disabled():
- reason = _("This rule is disabled")
+ reasons = [ _("This rule is disabled") ]
else:
- reason = rule.matches_host_and_item(watolib.Folder.current(),
self._hostname, self._item)
+ reasons = list(rule.get_mismatch_reasons(watolib.Folder.current(),
self._hostname, self._item))
+
+ matches_rule = not reasons
# Handle case where dict is constructed from rules
- if reason == True and ruleset.match_type() == "dict":
+ if matches_rule and ruleset.match_type() == "dict":
if not rule.value:
title = _("This rule matches, but does not define any
parameters.")
img = 'imatch'
@@ -13180,7 +13182,7 @@ class ModeEditRuleset(WatoMode):
img = 'pmatch'
match_keys.update(new_keys)
- elif reason == True and (not alread_matched or ruleset.match_type() ==
"all"):
+ elif matches_rule and (not alread_matched or ruleset.match_type() ==
"all"):
title = _("This rule matches for the host '%s'") %
self._hostname
if ruleset.item_type():
title += _(" and the %s '%s'.") %
(ruleset.item_name(), self._item)
@@ -13188,12 +13190,12 @@ class ModeEditRuleset(WatoMode):
title += "."
img = 'match'
alread_matched = True
- elif reason == True:
+ elif matches_rule:
title = _("This rule matches, but is overridden by a previous
rule.")
img = 'imatch'
alread_matched = True
else:
- title = _("This rule does not match: %s") % reason
+ title = _("This rule does not match: %s") % "
".join(reasons)
img = 'nmatch'
html.img("images/icon_rule%s.png" % img,
align="absmiddle", title=title, class_="icon")
@@ -15194,24 +15196,13 @@ class ModePatternEditor(WatoMode):
# Check if this rule applies to the given host/service
if self._hostname:
# If hostname (and maybe filename) try match it
- reason = rule.matches_host_and_item(watolib.Folder.current(),
self._hostname, self._item)
+ rule_matches = rule.matches_host_and_item(watolib.Folder.current(),
self._hostname, self._item)
elif self._item:
# If only a filename is given
- reason = rule.matches_item()
+ rule_matches = rule.matches_item()
else:
# If no host/file given match all rules
- reason = True
-
- match_img = ''
- if reason == True:
- # Applies to the given host/service
- reason_class = 'reason'
- # match_title/match_img are set below per pattern
- else:
- # not matching
- reason_class = 'noreason'
- match_img = 'nmatch'
- match_title = reason
+ rule_matches = True
html.begin_foldable_container("rule", "%s" % abs_rulenr,
True,
HTML("<b>Rule #%d</b>" % (abs_rulenr + 1)),
indent = False)
@@ -15228,7 +15219,11 @@ class ModePatternEditor(WatoMode):
for state, pattern, comment in pattern_list:
match_class = ''
disp_match_txt = ''
- if reason == True:
+ match_img = ''
+ if rule_matches:
+ # Applies to the given host/service
+ reason_class = 'reason'
+
matched = re.search(pattern, self._match_txt)
if matched:
@@ -15254,6 +15249,11 @@ class ModePatternEditor(WatoMode):
else:
match_img = 'nmatch'
match_title = _('This logfile pattern does not match the
given string.')
+ else:
+ # rule does not match
+ reason_class = 'noreason'
+ match_img = 'nmatch'
+ match_title = _('The rule conditions do not match.')
table.row(css=reason_class)
table.cell(_('Match'))
diff --git a/web/htdocs/watolib.py b/web/htdocs/watolib.py
index c10f4be..da1f52e 100644
--- a/web/htdocs/watolib.py
+++ b/web/htdocs/watolib.py
@@ -8005,7 +8005,7 @@ class Ruleset(object):
if rule.is_disabled():
continue
- if rule.matches_host_and_item(Folder.current(), hostname, service) != True:
+ if not rule.matches_host_and_item(Folder.current(), hostname, service):
continue
if self.match_type() == "all":
@@ -8266,37 +8266,38 @@ class Rule(object):
def is_ineffective(self):
hosts = Host.all()
for host_name, host in hosts.items():
- reason = self.matches_host_and_item(host.folder(), host_name, NO_ITEM)
- if reason == True:
+ if self.matches_host_and_item(host.folder(), host_name, NO_ITEM):
return False
return True
def matches_host_and_item(self, host_folder, hostname, item):
- reasons = []
+ """Whether or not the given folder/host/item matches this
rule"""
+ for reason in self.get_mismatch_reasons(host_folder, hostname, item):
+ return False
+ return True
+
+
+ def get_mismatch_reasons(self, host_folder, hostname, item):
+ """A generator that provides the reasons why a given
folder/host/item not matches this rule"""
host = host_folder.host(hostname)
if not self._matches_hostname(hostname):
- reasons.append(_("The host name does not match."))
+ yield _("The host name does not match.")
for tag in self.tag_specs:
if tag[0] != '/' and tag[0] != '!' and tag not in
host.tags():
- reasons.append(_("The host is missing the tag %s") % tag)
+ yield _("The host is missing the tag %s") % tag
elif tag[0] == '!' and tag[1:] in host.tags():
- reasons.append(_("The host has the tag %s") % tag)
+ yield _("The host has the tag %s") % tag
if not self.folder.is_transitive_parent_of(host_folder):
- reasons.append(_("The rule does not apply to the folder of the
host."))
+ yield _("The rule does not apply to the folder of the host.")
if item != NO_ITEM and self.ruleset.item_type():
if not self.matches_item(item):
- reasons.append(_("The %s \"%s\" does not match this
rule.") %
- (self.ruleset.item_name(), item))
-
- if not reasons:
- return True
- else:
- return " ".join(reasons)
+ yield _("The %s \"%s\" does not match this rule.") %
\
+ (self.ruleset.item_name(), item)
def _matches_hostname(self, hostname):