Module: check_mk
Branch: master
Commit: f841b31ae8f57294e238575baddff591f2d4bfed
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=f841b31ae8f572…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Sun Feb 24 18:44:11 2019 +0100
7182 Improved GUI extension error handling
When extending the standard GUI functionality, using either a manually
installed <tt>local/share/check_mk/web</tt> plugin or a Check_MK extension
package (MKP), exceptions may occur while loading the plugin.
In previous versions these exceptions caused the whole GUI to fail making it
impossible to repair the problem using the GUI, for example via the extension
package manager of the CEE/CME.
The extension related loading errors are now all catched and logged to the
<tt>var/log/web.log</tt> instead of making the whole application fail. In
addition to this, an error message will be shown on the "Extension packages"
WATO page. We've also added a new Analyze configuration check "Broken GUI
extensions" which will report a CRIT state when broken GUI extensions are
found.
Change-Id: I8c1230a7c7a5df11242b76c24b0ea107df27546e
---
.werks/7182 | 23 +++++++++++++
cmk/gui/plugins/wato/ac_tests.py | 27 +++++++++++++++
cmk/gui/utils.py | 39 +++++++++++++++-------
.../cmk/gui/watolib/test_analyze_configuration.py | 1 +
4 files changed, 78 insertions(+), 12 deletions(-)
diff --git a/.werks/7182 b/.werks/7182
new file mode 100644
index 0000000..f78b439
--- /dev/null
+++ b/.werks/7182
@@ -0,0 +1,23 @@
+Title: Improved GUI extension error handling
+Level: 2
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1551029903
+Class: feature
+
+When extending the standard GUI functionality, using either a manually
+installed <tt>local/share/check_mk/web</tt> plugin or a Check_MK extension
+package (MKP), exceptions may occur while loading the plugin.
+
+In previous versions these exceptions caused the whole GUI to fail making it
+impossible to repair the problem using the GUI, for example via the extension
+package manager of the CEE/CME.
+
+The extension related loading errors are now all catched and logged to the
+<tt>var/log/web.log</tt> instead of making the whole application fail. In
+addition to this, an error message will be shown on the "Extension packages"
+WATO page. We've also added a new Analyze configuration check "Broken GUI
+extensions" which will report a CRIT state when broken GUI extensions are
+found.
diff --git a/cmk/gui/plugins/wato/ac_tests.py b/cmk/gui/plugins/wato/ac_tests.py
index ec191fb..f8213c1 100644
--- a/cmk/gui/plugins/wato/ac_tests.py
+++ b/cmk/gui/plugins/wato/ac_tests.py
@@ -30,6 +30,7 @@ import subprocess
import requests
import urllib3
+import cmk.gui.utils
import cmk.gui.userdb as userdb
import cmk.gui.sites as sites
import cmk.gui.watolib as watolib
@@ -771,6 +772,32 @@ class ACTestSizeOfExtensions(ACTest):
@ac_test_registry.register
+class ACTestBrokenGUIExtension(ACTest):
+ def category(self):
+ return ACTestCategories.deprecations
+
+ def title(self):
+ return _("Broken GUI extensions")
+
+ def help(self):
+ return _(
+ "Since 1.6.0i1 broken GUI extensions don't block the whole GUI
initialization anymore. "
+ "Instead of this, the errors are logged in
<tt>var/log/web.log</tt>. In addition to this, "
+ "the errors are displayed here.")
+
+ def is_relevant(self):
+ return True
+
+ def execute(self):
+ errors = cmk.gui.utils.get_failed_plugins()
+ if not errors:
+ yield ACResultOK(_("No broken extensions were found."))
+
+ for plugin_path, e in errors:
+ yield ACResultCRIT(_("Loading \"%s\" failed: %s") %
(plugin_path, e))
+
+
+(a)ac_test_registry.register
class ACTestESXDatasources(ACTest):
def category(self):
return ACTestCategories.deprecations
diff --git a/cmk/gui/utils.py b/cmk/gui/utils.py
index 97e2457..a74a581 100644
--- a/cmk/gui/utils.py
+++ b/cmk/gui/utils.py
@@ -33,10 +33,12 @@ import re
import uuid
import marshal
import urlparse
+import itertools
import cmk.utils.paths
from cmk.gui.i18n import _
+from cmk.gui.log import logger
from cmk.gui.exceptions import MKUserError
@@ -158,13 +160,17 @@ def gen_id():
return str(uuid.uuid4())
-# Load all files below share/check_mk/web/plugins/WHAT into a
-# specified context (global variables). Also honors the
-# local-hierarchy for OMD
-# TODO: Couldn't we precompile all our plugins during packaging to make loading
faster?
-# TODO: Replace the execfile thing by some more pythonic plugin structure. But this
would
-# be a large rewrite :-/
+# This may not be moved to current_app.g, because this needs to be request
+# independent
+_failed_plugins = {}
+
+
+# Load all files below share/check_mk/web/plugins/WHAT into a specified context
+# (global variables). Also honors the local-hierarchy for OMD
+# TODO: This is kept for pre 1.6.0i1 plugins
def load_web_plugins(forwhat, globalvars):
+ _failed_plugins[forwhat] = []
+
for plugins_path in [
cmk.utils.paths.web_dir + "/plugins/" + forwhat,
cmk.utils.paths.local_web_dir + "/plugins/" + forwhat
@@ -175,10 +181,19 @@ def load_web_plugins(forwhat, globalvars):
for fn in sorted(os.listdir(plugins_path)):
file_path = plugins_path + "/" + fn
- if fn.endswith(".py") and not os.path.exists(file_path +
"c"):
- execfile(file_path, globalvars)
+ try:
+ if fn.endswith(".py") and not os.path.exists(file_path +
"c"):
+ execfile(file_path, globalvars)
+
+ elif fn.endswith(".pyc"):
+ code_bytes = file(file_path).read()[8:]
+ code = marshal.loads(code_bytes)
+ exec code in globalvars
+
+ except Exception as e:
+ logger.error("Failed to load plugin %s: %s", file_path, e,
exc_info=True)
+ _failed_plugins[forwhat].append((file_path, e))
+
- elif fn.endswith(".pyc"):
- code_bytes = file(file_path).read()[8:]
- code = marshal.loads(code_bytes)
- exec code in globalvars
+def get_failed_plugins():
+ return itertools.chain(*_failed_plugins.values())
diff --git a/tests/unit/cmk/gui/watolib/test_analyze_configuration.py
b/tests/unit/cmk/gui/watolib/test_analyze_configuration.py
index f66c44c..8081e21 100644
--- a/tests/unit/cmk/gui/watolib/test_analyze_configuration.py
+++ b/tests/unit/cmk/gui/watolib/test_analyze_configuration.py
@@ -11,6 +11,7 @@ def test_registered_ac_tests():
'ACTestApacheProcessUsage',
'ACTestBackupConfigured',
'ACTestBackupNotEncryptedConfigured',
+ 'ACTestBrokenGUIExtension',
'ACTestCheckMKHelperUsage',
'ACTestESXDatasources',
'ACTestGenericCheckHelperUsage',